Merge "Reference core-test-rules in MtsConscryptTestCases"
diff --git a/JavaLibrary.bp b/JavaLibrary.bp
index e5e2a69..6765907 100644
--- a/JavaLibrary.bp
+++ b/JavaLibrary.bp
@@ -223,7 +223,10 @@
 
     installable: false,
 
-    plugins: ["compat-changeid-annotation-processor"],
+    plugins: [
+        "compat-changeid-annotation-processor",
+        "unsupportedappusage-annotation-processor",
+    ],
 }
 
 platform_compat_config {
@@ -379,6 +382,7 @@
     sdk_version: "none",
     system_modules: "core-all-system-modules",
     patch_module: "java.base",
+    plugins: ["unsupportedappusage-annotation-processor"],
 }
 
 //
@@ -490,6 +494,7 @@
         "//frameworks/base/location/tests/locationtests",
         "//frameworks/base/core/tests/coretests",
         "//frameworks/base/wifi/tests",
+        "//cts/tests/tests/util",
     ],
     hostdex: true,
     srcs: [
diff --git a/NativeCode.bp b/NativeCode.bp
index 9619420..2041a92 100644
--- a/NativeCode.bp
+++ b/NativeCode.bp
@@ -92,6 +92,7 @@
     name: "libandroidio",
     visibility: [
         "//art/build/apex",
+        "//art/build/sdk",
         "//external/conscrypt",
     ],
     apex_available: [
@@ -214,11 +215,17 @@
 
     srcs: [
         "luni/src/test/native/libcore_dalvik_system_JniTest.cpp",
+        "luni/src/test/native/libcore_libcore_icu_LocaleDataTest.cpp",
         "luni/src/test/native/libcore_java_io_FileTest.cpp",
         "luni/src/test/native/libcore_java_lang_ThreadTest.cpp",
         "luni/src/test/native/libcore_java_nio_BufferTest.cpp",
         "luni/src/test/native/libcore_libcore_util_NativeAllocationRegistryTest.cpp",
     ],
+    shared_libs: [
+        "libicui18n",
+        "libicuuc",
+        "liblog",
+    ],
     target: {
         android: {
             shared_libs: ["libnativehelper_compat_libc++"],
@@ -228,6 +235,13 @@
         },
     },
 
+    cflags: [
+        // -DANDROID_LINK_SHARED_ICU4C to enable access to the full ICU4C.
+        // See external/icu/android_icu4c/include/uconfig_local.h
+        // for more information.
+        "-DANDROID_LINK_SHARED_ICU4C",
+    ],
+
     strip: {
         keep_symbols: true,
     },
diff --git a/TEST_MAPPING b/TEST_MAPPING
index f8c149d..8c0baae 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,7 +1,90 @@
 {
   "presubmit": [
     {
-      "name": "CtsSaxTestCases"
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "exclude-filter": "com.android.org.conscrypt.java.security.AlgorithmParameterGeneratorTestDH"
+        },
+        {
+          "exclude-filter": "com.android.org.conscrypt.java.security.KeyPairGeneratorTest"
+        },
+        {
+          "exclude-filter": "com.android.org.conscrypt.java.security.SignatureTest"
+        },
+        {
+          "exclude-filter": "com.android.org.conscrypt.javax.crypto.CipherBasicsTest"
+        },
+        {
+          "exclude-filter": "com.android.org.conscrypt.javax.net.ssl.KeyManagerFactoryTest"
+        },
+        {
+          "exclude-filter": "com.android.org.conscrypt.javax.net.ssl.SSLSocketVersionCompatibilityTest"
+        },
+        {
+          "exclude-filter": "libcore.java.lang.OldRuntimeTest"
+        },
+        {
+          "exclude-filter": "libcore.java.lang.OldThreadTest"
+        },
+        {
+          "exclude-filter": "libcore.java.lang.ref.FinalizeTest"
+        },
+        {
+          "exclude-filter": "libcore.java.math.BigIntegerTest"
+        },
+        {
+          "exclude-filter": "libcore.java.net.ConcurrentCloseTest"
+        },
+        {
+          "exclude-filter": "libcore.java.net.OldSocketTest"
+        },
+        {
+          "exclude-filter": "libcore.java.net.URLConnectionTest"
+        },
+        {
+          "exclude-filter": "libcore.java.nio.channels.DatagramChannelMulticastTest"
+        },
+        {
+          "exclude-filter": "libcore.libcore.net.NetworkSecurityPolicyTest"
+        },
+        {
+          "exclude-filter": "libcore.libcore.util.NativeAllocationRegistryTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.logging.tests.java.util.logging.SocketHandlerTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.tests.java.lang.ObjectTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.tests.java.lang.ProcessManagerTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.tests.java.math.OldBigIntegerTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.tests.java.net.InetAddressThreadTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.tests.java.nio.channels.DatagramChannelTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.tests.java.util.ScannerTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.tests.java.util.TimerTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.tests.java.util.WeakHashMapTest"
+        },
+        {
+          "exclude-filter": "org.apache.harmony.tests.javax.net.ssl.SSLSessionTest"
+        },
+        {
+          "exclude-filter": "tests.java.sql.StressTest"
+        }
+      ]
     }
   ]
-}
+}
\ No newline at end of file
diff --git a/benchmarks/src/benchmarks/LocaleDataBenchmark.java b/benchmarks/src/benchmarks/LocaleDataBenchmark.java
new file mode 100644
index 0000000..adf6768
--- /dev/null
+++ b/benchmarks/src/benchmarks/LocaleDataBenchmark.java
@@ -0,0 +1,40 @@
+/*
+ * 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 benchmarks;
+
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import java.util.Locale;
+import libcore.icu.LocaleData;
+
+public final class LocaleDataBenchmark {
+    private static final Locale[] TEST_LOCALES = new Locale[]  {
+        Locale.forLanguageTag("en-US"),
+        Locale.forLanguageTag("jp-JP"),
+        Locale.forLanguageTag("es-419"),
+        Locale.forLanguageTag("ar-EG"),
+        Locale.forLanguageTag("zh-CN"),
+    };
+
+    public void timeInitLocaleData(int reps) {
+        for (int rep = 0; rep < reps; ++rep) {
+            for (Locale locale : TEST_LOCALES) {
+                LocaleData.initLocaleData(locale);
+            }
+        }
+    }
+}
diff --git a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
index 0339b4d..475acd9 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
@@ -67,6 +68,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/expectations/virtualdeviceknownfailures.txt b/expectations/virtualdeviceknownfailures.txt
index 756aa53..4ab4074 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/net/MulticastSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
index a24a67b..67eb932 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
@@ -17,6 +17,13 @@
 
 package org.apache.harmony.tests.java.net;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import java.io.IOException;
 import java.net.BindException;
 import java.net.DatagramPacket;
@@ -32,12 +39,15 @@
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.List;
-import libcore.junit.junit3.TestCaseWithRules;
+
 import libcore.junit.util.ResourceLeakageDetector;
+
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.rules.TestRule;
+import org.junit.Test;
 
-public class MulticastSocketTest extends TestCaseWithRules {
+public class MulticastSocketTest {
     @Rule
     public TestRule guardRule = ResourceLeakageDetector.getRule();
 
@@ -63,8 +73,8 @@
     private NetworkInterface ipv6NetworkInterface;
     private boolean supportsMulticast;
 
-    @Override
-    protected void setUp() throws Exception {
+    @Before
+    public void setUp() throws Exception {
         // The loopback interface isn't actually useful for sending/receiving multicast messages
         // but it can be used as a dummy for tests where that does not matter.
         loopbackInterface = NetworkInterface.getByInetAddress(InetAddress.getLoopbackAddress());
@@ -104,7 +114,8 @@
                 ipv4NetworkInterface != null && ipv6NetworkInterface != null);
     }
 
-    public void test_Constructor() throws IOException {
+    @Test
+    public void constructor() throws IOException {
         if (!supportsMulticast) {
             return;
         }
@@ -116,7 +127,8 @@
         s.close();
     }
 
-    public void test_ConstructorI() throws IOException {
+    @Test
+    public void constructorI() throws IOException {
         if (!supportsMulticast) {
             return;
         }
@@ -130,7 +142,8 @@
         dup.close();
     }
 
-    public void test_getInterface() throws Exception {
+    @Test
+    public void getInterface() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -157,7 +170,8 @@
         mss.close();
     }
 
-    public void test_getNetworkInterface() throws IOException {
+    @Test
+    public void getNetworkInterface() throws IOException {
         if (!supportsMulticast) {
             return;
         }
@@ -202,7 +216,8 @@
         mss.close();
     }
 
-    public void test_getTimeToLive() throws Exception {
+    @Test
+    public void getTimeToLive() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -214,7 +229,8 @@
         mss.close();
     }
 
-    public void test_getTTL() throws Exception {
+    @Test
+    public void getTTL() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -224,14 +240,16 @@
         mss.close();
     }
 
-    public void test_joinGroupLjava_net_InetAddress_IPv4() throws Exception {
+    @Test
+    public void joinGroupLjava_net_InetAddress_IPv4() throws Exception {
         if (!supportsMulticast) {
             return;
         }
         test_joinGroupLjava_net_InetAddress(GOOD_IPv4);
     }
 
-    public void test_joinGroupLjava_net_InetAddress_IPv6() throws Exception {
+    @Test
+    public void joinGroupLjava_net_InetAddress_IPv6() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -258,7 +276,8 @@
         receivingSocket.close();
     }
 
-    public void test_joinGroup_null_null() throws Exception {
+    @Test
+    public void joinGroup_null_null() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -271,7 +290,8 @@
         mss.close();
     }
 
-    public void test_joinGroup_non_multicast_address_IPv4() throws Exception {
+    @Test
+    public void joinGroup_non_multicast_address_IPv4() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -284,7 +304,8 @@
         mss.close();
     }
 
-    public void test_joinGroup_non_multicast_address_IPv6() throws Exception {
+    @Test
+    public void joinGroup_non_multicast_address_IPv6() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -297,35 +318,39 @@
         mss.close();
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4()
+    @Test
+    public void joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4()
             throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+        check_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
                 ipv4NetworkInterface, GOOD_IPv4, BAD_IPv4);
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6()
+    @Test
+    public void joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6()
             throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+        check_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
                 ipv6NetworkInterface, GOOD_IPv6, BAD_IPv6);
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4_nullInterface()
+    @Test
+    public void joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4_nullInterface()
             throws Exception {
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(null, GOOD_IPv4, BAD_IPv4);
+        check_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(null, GOOD_IPv4, BAD_IPv4);
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6_nullInterface()
+    @Test
+    public void joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6_nullInterface()
             throws Exception {
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(null, GOOD_IPv6, BAD_IPv6);
+        check_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(null, GOOD_IPv6, BAD_IPv6);
     }
 
-    private void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+    private void check_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
             NetworkInterface networkInterface, InetAddress group, InetAddress group2)
             throws Exception {
         // Create the sending socket and specify the interface to use as needed (otherwise use the
@@ -383,7 +408,8 @@
         sendingSocket.close();
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface() throws Exception {
+    @Test
+    public void joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -453,25 +479,27 @@
         }
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv4()
+    @Test
+    public void joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv4()
             throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
+        check_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
                 ipv4NetworkInterface, GOOD_IPv4);
     }
 
-    public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv6()
+    @Test
+    public void joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv6()
             throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
+        check_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
                 ipv6NetworkInterface, GOOD_IPv6);
     }
 
-    private void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
+    private void check_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins(
             NetworkInterface networkInterface, InetAddress group) throws Exception {
         // Validate that we can join the same address on two different interfaces but not on the
         // same interface.
@@ -487,21 +515,23 @@
         mss.close();
     }
 
-    public void test_leaveGroupLjava_net_InetAddress_IPv4() throws Exception {
+    @Test
+    public void leaveGroupLjava_net_InetAddress_IPv4() throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_leaveGroupLjava_net_InetAddress(GOOD_IPv4);
+        check_leaveGroupLjava_net_InetAddress(GOOD_IPv4);
     }
 
-    public void test_leaveGroupLjava_net_InetAddress_IPv6() throws Exception {
+    @Test
+    public void leaveGroupLjava_net_InetAddress_IPv6() throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_leaveGroupLjava_net_InetAddress(GOOD_IPv6);
+        check_leaveGroupLjava_net_InetAddress(GOOD_IPv6);
     }
 
-    private void test_leaveGroupLjava_net_InetAddress(InetAddress group) throws Exception {
+    private void check_leaveGroupLjava_net_InetAddress(InetAddress group) throws Exception {
         String msg = "Hello World";
         MulticastSocket mss = new MulticastSocket(0);
         InetSocketAddress groupAddress = new InetSocketAddress(group, mss.getLocalPort());
@@ -516,7 +546,8 @@
         mss.close();
     }
 
-    public void test_leaveGroup_null_null() throws Exception {
+    @Test
+    public void leaveGroup_null_null() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -529,7 +560,8 @@
         mss.close();
     }
 
-    public void test_leaveGroup_non_multicast_address_IPv4() throws Exception {
+    @Test
+    public void leaveGroup_non_multicast_address_IPv4() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -542,7 +574,8 @@
         mss.close();
     }
 
-    public void test_leaveGroup_non_multicast_address_IPv6() throws Exception {
+    @Test
+    public void leaveGroup_non_multicast_address_IPv6() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -555,25 +588,27 @@
         mss.close();
     }
 
-    public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4()
+    @Test
+    public void leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4()
             throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+        check_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
                 ipv4NetworkInterface, GOOD_IPv4, BAD_IPv4);
     }
 
-    public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6()
+    @Test
+    public void leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6()
             throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+        check_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
                 ipv6NetworkInterface, GOOD_IPv6, BAD_IPv6);
     }
 
-    private void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
+    private void check_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface(
             NetworkInterface networkInterface, InetAddress group, InetAddress group2)
             throws Exception {
         SocketAddress groupSockAddr = null;
@@ -609,21 +644,23 @@
         }
     }
 
-    public void test_sendLjava_net_DatagramPacketB_IPv4() throws Exception {
+    @Test
+    public void sendLjava_net_DatagramPacketB_IPv4() throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_sendLjava_net_DatagramPacketB(GOOD_IPv4);
+        check_sendLjava_net_DatagramPacketB(GOOD_IPv4);
     }
 
-    public void test_sendLjava_net_DatagramPacketB_IPv6() throws Exception {
+    @Test
+    public void sendLjava_net_DatagramPacketB_IPv6() throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_sendLjava_net_DatagramPacketB(GOOD_IPv6);
+        check_sendLjava_net_DatagramPacketB(GOOD_IPv6);
     }
 
-    private void test_sendLjava_net_DatagramPacketB(InetAddress group) throws Exception {
+    private void check_sendLjava_net_DatagramPacketB(InetAddress group) throws Exception {
         String msg = "Hello World";
         MulticastSocket sendingSocket = new MulticastSocket(0);
         MulticastSocket receivingSocket = createReceivingSocket(sendingSocket.getLocalPort());
@@ -641,7 +678,8 @@
         receivingSocket.close();
     }
 
-    public void test_setInterfaceLjava_net_InetAddress() throws Exception {
+    @Test
+    public void setInterfaceLjava_net_InetAddress() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -662,14 +700,16 @@
         mss.close();
     }
 
-    public void test_setInterface_unbound_address_IPv4() throws Exception {
+    @Test
+    public void setInterface_unbound_address_IPv4() throws Exception {
         if (!supportsMulticast) {
             return;
         }
         test_setInterface_unbound_address(GOOD_IPv4);
     }
 
-    public void test_setInterface_unbound_address_IPv6() throws Exception {
+    @Test
+    public void setInterface_unbound_address_IPv6() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -687,7 +727,8 @@
         mss.close();
     }
 
-    public void test_setNetworkInterfaceLjava_net_NetworkInterface_null() throws Exception {
+    @Test
+    public void setNetworkInterfaceLjava_net_NetworkInterface_null() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -701,7 +742,8 @@
         mss.close();
     }
 
-    public void test_setNetworkInterfaceLjava_net_NetworkInterface_round_trip() throws Exception {
+    @Test
+    public void setNetworkInterfaceLjava_net_NetworkInterface_round_trip() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -713,21 +755,23 @@
         mss.close();
     }
 
-    public void test_setNetworkInterfaceLjava_net_NetworkInterface_IPv4() throws Exception {
+    @Test
+    public void setNetworkInterfaceLjava_net_NetworkInterface_IPv4() throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_setNetworkInterfaceLjava_net_NetworkInterface(GOOD_IPv4);
+        check_setNetworkInterfaceLjava_net_NetworkInterface(GOOD_IPv4);
     }
 
-    public void test_setNetworkInterfaceLjava_net_NetworkInterface_IPv6() throws Exception {
+    @Test
+    public void setNetworkInterfaceLjava_net_NetworkInterface_IPv6() throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_setNetworkInterfaceLjava_net_NetworkInterface(GOOD_IPv6);
+        check_setNetworkInterfaceLjava_net_NetworkInterface(GOOD_IPv6);
     }
 
-    private void test_setNetworkInterfaceLjava_net_NetworkInterface(InetAddress group)
+    private void check_setNetworkInterfaceLjava_net_NetworkInterface(InetAddress group)
             throws IOException, InterruptedException {
         // Set up the receiving socket and join the group.
         Enumeration theInterfaces = NetworkInterface.getNetworkInterfaces();
@@ -761,7 +805,8 @@
         }
     }
 
-    public void test_setTimeToLiveI() throws Exception {
+    @Test
+    public void setTimeToLiveI() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -773,7 +818,8 @@
         mss.close();
     }
 
-    public void test_setTTLB() throws Exception {
+    @Test
+    public void setTTLB() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -783,7 +829,8 @@
         mss.close();
     }
 
-    public void test_ConstructorLjava_net_SocketAddress() throws Exception {
+    @Test
+    public void constructorLjava_net_SocketAddress() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -817,7 +864,8 @@
         s.close();
     }
 
-    public void test_getLoopbackMode() throws Exception {
+    @Test
+    public void getLoopbackMode() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -829,7 +877,8 @@
         assertTrue("should be closed", ms.isClosed());
     }
 
-    public void test_setLoopbackModeZ() throws Exception {
+    @Test
+    public void setLoopbackModeZ() throws Exception {
         if (!supportsMulticast) {
             return;
         }
@@ -842,21 +891,23 @@
         assertTrue("should be closed", ms.isClosed());
     }
 
-    public void test_setLoopbackModeSendReceive_IPv4() throws Exception {
+    @Test
+    public void setLoopbackModeSendReceive_IPv4() throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_setLoopbackModeSendReceive(GOOD_IPv4);
+        check_setLoopbackModeSendReceive(GOOD_IPv4);
     }
 
-    public void test_setLoopbackModeSendReceive_IPv6() throws Exception {
+    @Test
+    public void setLoopbackModeSendReceive_IPv6() throws Exception {
         if (!supportsMulticast) {
             return;
         }
-        test_setLoopbackModeSendReceive(GOOD_IPv6);
+        check_setLoopbackModeSendReceive(GOOD_IPv6);
     }
 
-    private void test_setLoopbackModeSendReceive(InetAddress group) throws IOException {
+    private void check_setLoopbackModeSendReceive(InetAddress group) throws IOException {
         // Test send receive.
         final String message = "Hello, world!";
 
@@ -878,7 +929,8 @@
         socket.close();
     }
 
-    public void test_setReuseAddressZ() throws Exception {
+    @Test
+    public void setReuseAddressZ() throws Exception {
         if (!supportsMulticast) {
             return;
         }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/org/apache/harmony/kernel/dalvik/ThreadsTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/org/apache/harmony/kernel/dalvik/ThreadsTest.java
index 37c6086..e8f1bc5 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/org/apache/harmony/kernel/dalvik/ThreadsTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/org/apache/harmony/kernel/dalvik/ThreadsTest.java
@@ -81,6 +81,7 @@
     public void test_parkFor_3() throws Exception {
         CyclicBarrier barrier = new CyclicBarrier(1);
         Parker parker = new Parker(barrier, false, 1000);
+        parker.disableRetry();
         Thread parkerThread = new Thread(parker);
 
         UNSAFE.unpark(parkerThread);
@@ -123,6 +124,7 @@
     public void test_parkUntil_3() throws Exception {
         CyclicBarrier barrier = new CyclicBarrier(1);
         Parker parker = new Parker(barrier, true, 1000);
+        parker.disableRetry();
         Thread parkerThread = new Thread(parker);
 
         UNSAFE.unpark(parkerThread);
@@ -139,6 +141,8 @@
      */
     private static class Parker implements Runnable {
 
+        private static final long NANOS_PER_MILLI = 1_000_000L;
+
         private final CyclicBarrier barrier;
 
         /** whether {@link #amount} is milliseconds to wait in an
@@ -146,6 +150,8 @@
          * in a relative fashion (<code>false</code>) */
         private final boolean absolute;
 
+        private boolean retryDisabled;
+
         /** amount to wait (see above) */
         private final long amount;
 
@@ -153,10 +159,10 @@
         private boolean completed;
 
         /** recorded start time */
-        private long startMillis;
+        private long startNanos;
 
         /** recorded end time */
-        private long endMillis;
+        private long endNanos;
 
         /**
          * Construct an instance.
@@ -168,9 +174,17 @@
         public Parker(CyclicBarrier barrier, boolean absolute, long parkMillis) {
             this.barrier = barrier;
             this.absolute = absolute;
-
+            // this.retryDisabled = false;
+            if (parkMillis < 10) {
+              // Doesn't work well with our retry logic, and likely to be flakey.
+              throw new AssertionError("Unexpectedly short park timeout.");
+            }
             // Multiply by 1000000 because parkFor() takes nanoseconds.
-            this.amount = absolute ? parkMillis : parkMillis * 1000000;
+            this.amount = absolute ? parkMillis : parkMillis * NANOS_PER_MILLI;
+        }
+
+        public void disableRetry() {
+          retryDisabled = true;
         }
 
         public void run() {
@@ -181,20 +195,29 @@
             }
             boolean absolute = this.absolute;
             long amount = this.amount;
-            long startNanos = System.nanoTime();
+            long startNs = System.nanoTime();
             long start = System.currentTimeMillis();
 
-            if (absolute) {
-                UNSAFE.park(true, start + amount);
-            } else {
-                UNSAFE.park(false, amount);
+            for (int i = 0; i < 2; ++i) {
+                if (absolute) {
+                    UNSAFE.park(true, start + amount);
+                } else {
+                    UNSAFE.park(false, amount);
+                }
+                // park() may wake up spuriously. For our implementation, this
+                // should be unlikely, except there are cases in which the
+                // initial attempt returns immediately. Try a second time, but
+                // only in that case.
+                if (retryDisabled || System.currentTimeMillis() - start > 1L) {
+                  break;
+                }
             }
 
-            long endNanos = System.nanoTime();
+            long endNs = System.nanoTime();
 
             synchronized (this) {
-                startMillis = startNanos / 1000000;
-                endMillis = endNanos / 1000000;
+                startNanos = startNs;
+                endNanos = endNs;
                 completed = true;
                 notifyAll();
             }
@@ -219,25 +242,23 @@
                     }
                 }
 
-                return endMillis - startMillis;
+                return (endNanos - startNanos) / NANOS_PER_MILLI;
             }
         }
 
         /**
-         * Asserts that the actual duration is within 10% of the
+         * Asserts that the actual duration is within 150-200 msecs of the
          * given expected time.
+         * Observe that small errors in either direction are normal here; for a
+         * number of tests the value will be too small if the Parker thread
+         * starts late, e.g. because it doesn't get a time slice soon enough.
          *
          * @param expectedMillis the expected duration, in milliseconds
          */
         public void assertDurationIsInRange(long expectedMillis) {
-            /*
-             * Allow a bit more slop for the maximum on "expected
-             * instantaneous" results.
-             */
-            long minimum = (long) ((double) expectedMillis * 0.80);
-            long maximum =
-                Math.max((long) ((double) expectedMillis * 1.20), 10);
-            long waitMillis = Math.max(expectedMillis * 10, 1000);
+            long minimum = Math.max(expectedMillis - 150L, 0L);
+            long maximum = expectedMillis + 200L;
+            long waitMillis = Math.max(expectedMillis * 10L, 1000L);
             long duration = getDurationMillis(waitMillis);
 
             if (duration < minimum) {
diff --git a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
index ea6e576..c073f1d 100644
--- a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
+++ b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
@@ -956,7 +956,7 @@
      * Uninteresting threads are filtered out.
      */
     static void dumpTestThreads() {
-        // Android-change no ThreadMXBean
+        // Android-removed: no ThreadMXBean.
         // ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
         // System.err.println("------ stacktrace dump start ------");
         // for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
@@ -1089,7 +1089,7 @@
      * getPolicy/setPolicy.
      */
     public void runWithPermissions(Runnable r, Permission... permissions) {
-        // Android-changed: no SecurityManager
+        // Android-removed: no SecurityManager.
         // SecurityManager sm = System.getSecurityManager();
         // if (sm == null) {
         //     r.run();
@@ -1107,7 +1107,7 @@
      */
     public void runWithSecurityManagerWithPermissions(Runnable r,
                                                       Permission... permissions) {
-        // Android-changed: no SecurityManager
+        // Android-removed: no SecurityManager.
         // SecurityManager sm = System.getSecurityManager();
         // if (sm == null) {
         //     Policy savedPolicy = Policy.getPolicy();
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 970dcc2..482464f 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;
 
 /**
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/libcore/icu/ICU.java b/luni/src/main/java/libcore/icu/ICU.java
index f6e5fed..c23c91f7 100644
--- a/luni/src/main/java/libcore/icu/ICU.java
+++ b/luni/src/main/java/libcore/icu/ICU.java
@@ -373,8 +373,6 @@
   private static native String[] getISOLanguagesNative();
   private static native String[] getISOCountriesNative();
 
-  static native boolean initLocaleDataNative(String languageTag, LocaleData result);
-
   /**
    * Takes a BCP-47 language tag (Locale.toLanguageTag()). e.g. en-US, not en_US
    */
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index ea6fe6f..9745bc0 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -19,7 +19,13 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.icu.impl.ICUData;
 import android.icu.impl.ICUResourceBundle;
+import android.icu.text.DateFormatSymbols;
+import android.icu.text.DecimalFormat;
+import android.icu.text.DecimalFormatSymbols;
+import android.icu.text.NumberFormat;
 import android.icu.text.NumberingSystem;
+import android.icu.util.Calendar;
+import android.icu.util.GregorianCalendar;
 import android.icu.util.UResourceBundle;
 
 import java.text.DateFormat;
@@ -92,11 +98,9 @@
     @libcore.api.CorePlatformApi
     public String[] tinyStandAloneWeekdayNames; // "S", ...
 
-    // Used by frameworks/base DateSorter and DateUtils.
-    @libcore.api.CorePlatformApi
-    public String yesterday; // "Yesterday".
+    // today and tomorrow is only kept for @UnsupportedAppUsage.
+    // Their value is hard-coded, not localized.
     @UnsupportedAppUsage
-    @libcore.api.CorePlatformApi
     public String today; // "Today".
     @UnsupportedAppUsage
     public String tomorrow; // "Tomorrow".
@@ -144,9 +148,6 @@
     public String exponentSeparator;
     public String infinity;
     public String NaN;
-    // Also used by Currency.
-    public String currencySymbol;
-    public String internationalCurrencySymbol;
 
     // Used by DecimalFormat and NumberFormat.
     public String numberPattern;
@@ -155,6 +156,8 @@
     public String percentPattern;
 
     private LocaleData() {
+        today = "Today";
+        tomorrow = "Tomorrow";
     }
 
     @UnsupportedAppUsage
@@ -241,11 +244,16 @@
         throw new AssertionError();
     }
 
-    private static LocaleData initLocaleData(Locale locale) {
+    /*
+     * This method is made public for testing
+     */
+    public static LocaleData initLocaleData(Locale locale) {
         LocaleData localeData = new LocaleData();
-        if (!ICU.initLocaleDataNative(locale.toLanguageTag(), localeData)) {
-            throw new AssertionError("couldn't initialize LocaleData for locale " + locale);
-        }
+
+        localeData.initializeDateTimePatterns(locale);
+        localeData.initializeDateFormatData(locale);
+        localeData.initializeDecimalFormatData(locale);
+        localeData.initializeCalendarData(locale);
 
         // Libcore localizes pattern separator while ICU doesn't. http://b/112080617
         initializePatternSeparator(localeData, locale);
@@ -296,7 +304,7 @@
         if (!"latn".equals(nsName)) {
             try {
                 patternSeparator = rb.getStringWithFallback(
-                    "NumberElements/" + nsName +"/symbols/list");
+                    "NumberElements/" + nsName + "/symbols/list");
             } catch (MissingResourceException e) {
                 // Try Latin numbering system later
             }
@@ -317,4 +325,123 @@
         // Pattern separator in libcore supports single java character only.
         localeData.patternSeparator = patternSeparator.charAt(0);
     }
-}
+
+    private void initializeDateFormatData(Locale locale) {
+        DateFormatSymbols dfs = new DateFormatSymbols(GregorianCalendar.class, locale);
+
+        longMonthNames = dfs.getMonths(DateFormatSymbols.FORMAT, DateFormatSymbols.WIDE);
+        shortMonthNames = dfs.getMonths(DateFormatSymbols.FORMAT, DateFormatSymbols.ABBREVIATED);
+        tinyMonthNames = dfs.getMonths(DateFormatSymbols.FORMAT, DateFormatSymbols.NARROW);
+        longWeekdayNames = dfs.getWeekdays(DateFormatSymbols.FORMAT, DateFormatSymbols.WIDE);
+        shortWeekdayNames = dfs
+            .getWeekdays(DateFormatSymbols.FORMAT, DateFormatSymbols.ABBREVIATED);
+        tinyWeekdayNames = dfs.getWeekdays(DateFormatSymbols.FORMAT, DateFormatSymbols.NARROW);
+
+        longStandAloneMonthNames = dfs
+            .getMonths(DateFormatSymbols.STANDALONE, DateFormatSymbols.WIDE);
+        shortStandAloneMonthNames = dfs
+            .getMonths(DateFormatSymbols.STANDALONE, DateFormatSymbols.ABBREVIATED);
+        tinyStandAloneMonthNames = dfs
+            .getMonths(DateFormatSymbols.STANDALONE, DateFormatSymbols.NARROW);
+        longStandAloneWeekdayNames = dfs
+            .getWeekdays(DateFormatSymbols.STANDALONE, DateFormatSymbols.WIDE);
+        shortStandAloneWeekdayNames = dfs
+            .getWeekdays(DateFormatSymbols.STANDALONE, DateFormatSymbols.ABBREVIATED);
+        tinyStandAloneWeekdayNames = dfs
+            .getWeekdays(DateFormatSymbols.STANDALONE, DateFormatSymbols.NARROW);
+
+        String[] ampmNarrowStrings = dfs.getAmpmNarrowStrings();
+        narrowAm = ampmNarrowStrings[0];
+        narrowPm = ampmNarrowStrings[1];
+
+        amPm = dfs.getAmPmStrings();
+        eras = dfs.getEras();
+
+    }
+
+    private void initializeDecimalFormatData(Locale locale) {
+        DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
+
+        decimalSeparator = dfs.getDecimalSeparator();
+        groupingSeparator = dfs.getGroupingSeparator();
+        patternSeparator = dfs.getPatternSeparator();
+        percent = dfs.getPercentString();
+        perMill = dfs.getPerMillString();
+        monetarySeparator = dfs.getMonetaryDecimalSeparator();
+        minusSign = dfs.getMinusSignString();
+        exponentSeparator = dfs.getExponentSeparator();
+        infinity = dfs.getInfinity();
+        NaN = dfs.getNaN();
+        zeroDigit = dfs.getZeroDigit();
+
+        DecimalFormat df = (DecimalFormat) NumberFormat
+            .getInstance(locale, NumberFormat.NUMBERSTYLE);
+        numberPattern = df.toPattern();
+
+        df = (DecimalFormat) NumberFormat.getInstance(locale, NumberFormat.CURRENCYSTYLE);
+        currencyPattern = df.toPattern();
+
+        df = (DecimalFormat) NumberFormat.getInstance(locale, NumberFormat.PERCENTSTYLE);
+        percentPattern = df.toPattern();
+
+    }
+
+    private void initializeCalendarData(Locale locale) {
+        Calendar calendar = Calendar.getInstance(locale);
+
+        firstDayOfWeek = calendar.getFirstDayOfWeek();
+        minimalDaysInFirstWeek = calendar.getMinimalDaysInFirstWeek();
+    }
+
+    private void initializeDateTimePatterns(Locale locale) {
+        try {
+            ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle.getBundleInstance(
+                ICUData.ICU_BASE_NAME, locale);
+            rb = rb.getWithFallback("calendar/gregorian/DateTimePatterns");
+            fullTimeFormat = getStringOrFirstArrayElement(rb, 0);
+            longTimeFormat = getStringOrFirstArrayElement(rb, 1);
+            mediumTimeFormat = getStringOrFirstArrayElement(rb, 2);
+            shortTimeFormat = getStringOrFirstArrayElement(rb, 3);
+            fullDateFormat = getStringOrFirstArrayElement(rb, 4);
+            longDateFormat = getStringOrFirstArrayElement(rb, 5);
+            mediumDateFormat = getStringOrFirstArrayElement(rb, 6);
+            shortDateFormat = getStringOrFirstArrayElement(rb, 7);
+        } catch (MissingResourceException e) {
+            // Preserve legacy behavior throwing AssertionError for missing resource.
+            throw new AssertionError(e);
+        }
+    }
+
+    private static String getStringOrFirstArrayElement(UResourceBundle rb, int index) {
+        try {
+            UResourceBundle currentBundle = rb.get(index);
+            int type = currentBundle.getType();
+            final String result;
+            switch(type) {
+                case UResourceBundle.STRING:
+                    result = currentBundle.getString();
+                    break;
+                case UResourceBundle.ARRAY:
+                    // In case there is an array, Android currently only cares about the
+                    // first string of that array, the rest of the array is used by ICU
+                    // for additional data ignored by Android.
+                    result = currentBundle.getString(0);
+                    break;
+                default:
+                  // Preserve legacy behavior of setting null
+                    result = null;
+                    System.logE(String.format(
+                        "Unsupported type when setting String field from ICU resource (type %d)",
+                        type)
+                    );
+            }
+            return result;
+        } catch (MissingResourceException e) {
+            // Preserve legacy behavior of avoiding throwing for missing resource.
+            System.logE(String.format(
+                "Error setting String field from ICU resource (index %d)", index), e
+            );
+            return null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index aa66f14..0554d6d 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -469,16 +469,13 @@
     /**
      * java.io only throws FileNotFoundException when opening files, regardless of what actually
      * went wrong. Additionally, java.io is more restrictive than POSIX when it comes to opening
-     * directories: POSIX says read-only is okay, but java.io doesn't even allow that. We also
-     * have an Android-specific hack to alter the default permissions.
+     * directories: POSIX says read-only is okay, but java.io doesn't even allow that.
      */
     @libcore.api.CorePlatformApi
     public static FileDescriptor open(String path, int flags) throws FileNotFoundException {
         FileDescriptor fd = null;
         try {
-            // On Android, we don't want default permissions to allow global access.
-            int mode = ((flags & O_ACCMODE) == O_RDONLY) ? 0 : 0600;
-            fd = Libcore.os.open(path, flags, mode);
+            fd = Libcore.os.open(path, flags, 0666);
             // Posix open(2) fails with EISDIR only if you ask for write permission.
             // Java disallows reading directories too.
             if (S_ISDIR(Libcore.os.fstat(fd).st_mode)) {
diff --git a/luni/src/main/java/libcore/timezone/CountryTimeZones.java b/luni/src/main/java/libcore/timezone/CountryTimeZones.java
index 4ff8470..3efe927 100644
--- a/luni/src/main/java/libcore/timezone/CountryTimeZones.java
+++ b/luni/src/main/java/libcore/timezone/CountryTimeZones.java
@@ -28,49 +28,13 @@
 
 /**
  * Information about a country's time zones.
+ *
  * @hide
  */
 @libcore.api.CorePlatformApi
 public final class CountryTimeZones {
 
     /**
-     * The result of lookup up a time zone using offset information (and possibly more).
-     * @hide
-     */
-    @libcore.api.CorePlatformApi
-    public static final class OffsetResult {
-
-        /** A zone that matches the supplied criteria. See also {@link #isOnlyMatch}. */
-        private final TimeZone timeZone;
-
-        /** True if there is one match for the supplied criteria */
-        private final boolean isOnlyMatch;
-
-        public OffsetResult(TimeZone timeZone, boolean isOnlyMatch) {
-            this.timeZone = java.util.Objects.requireNonNull(timeZone);
-            this.isOnlyMatch = isOnlyMatch;
-        }
-
-        @libcore.api.CorePlatformApi
-        public TimeZone getTimeZone() {
-            return timeZone;
-        }
-
-        @libcore.api.CorePlatformApi
-        public boolean isOnlyMatch() {
-            return isOnlyMatch;
-        }
-
-        @Override
-        public String toString() {
-            return "Result{"
-                    + "timeZone='" + timeZone + '\''
-                    + ", isOnlyMatch=" + isOnlyMatch
-                    + '}';
-        }
-    }
-
-    /**
      * A mapping to a time zone ID with some associated metadata.
      *
      * @hide
@@ -186,6 +150,44 @@
         }
     }
 
+    /**
+     * The result of lookup up a time zone using offset information (and possibly more).
+     *
+     * @hide
+     */
+    @libcore.api.CorePlatformApi
+    public static final class OffsetResult {
+
+        /** A zone that matches the supplied criteria. See also {@link #isOnlyMatch}. */
+        private final TimeZone timeZone;
+
+        /** True if there is one match for the supplied criteria */
+        private final boolean isOnlyMatch;
+
+        public OffsetResult(TimeZone timeZone, boolean isOnlyMatch) {
+            this.timeZone = Objects.requireNonNull(timeZone);
+            this.isOnlyMatch = isOnlyMatch;
+        }
+
+        @libcore.api.CorePlatformApi
+        public TimeZone getTimeZone() {
+            return timeZone;
+        }
+
+        @libcore.api.CorePlatformApi
+        public boolean isOnlyMatch() {
+            return isOnlyMatch;
+        }
+
+        @Override
+        public String toString() {
+            return "OffsetResult{"
+                    + "timeZone(ID)='" + timeZone.getID() + '\''
+                    + ", isOnlyMatch=" + isOnlyMatch
+                    + '}';
+        }
+    }
+
     private final String countryIso;
     private final String defaultTimeZoneId;
     /**
@@ -205,7 +207,7 @@
     private CountryTimeZones(String countryIso, String defaultTimeZoneId,
             boolean defaultTimeZoneBoosted, boolean everUsesUtc,
             List<TimeZoneMapping> timeZoneMappings) {
-        this.countryIso = java.util.Objects.requireNonNull(countryIso);
+        this.countryIso = Objects.requireNonNull(countryIso);
         this.defaultTimeZoneId = defaultTimeZoneId;
         this.defaultTimeZoneBoosted = defaultTimeZoneBoosted;
         this.everUsesUtc = everUsesUtc;
@@ -260,16 +262,27 @@
     }
 
     /**
-     * Returns true if the ISO code for the country is a match for the one specified.
+     * Returns true if the ISO code for the country is a case-insensitive match for the one
+     * supplied.
      */
     @libcore.api.CorePlatformApi
-    public boolean isForCountryCode(String countryIso) {
+    public boolean matchesCountryCode(String countryIso) {
         return this.countryIso.equals(normalizeCountryIso(countryIso));
     }
 
     /**
-     * Returns the default time zone for the country. Can return null in cases when no data is
-     * available or the time zone ID provided to
+     * Returns the default time zone ID for the country. Can return {@code null} in cases when no
+     * data is available or the time zone ID provided to
+     * {@link #createValidated(String, String, boolean, boolean, List, String)} was not recognized.
+     */
+    @libcore.api.CorePlatformApi
+    public String getDefaultTimeZoneId() {
+        return defaultTimeZoneId;
+    }
+
+    /**
+     * Returns the default time zone for the country. Can return {@code null} in cases when no data
+     * is available or the time zone ID provided to
      * {@link #createValidated(String, String, boolean, boolean, List, String)} was not recognized.
      */
     @libcore.api.CorePlatformApi
@@ -287,18 +300,10 @@
     }
 
     /**
-     * Returns the default time zone ID for the country. Can return null in cases when no data is
-     * available or the time zone ID provided to
-     * {@link #createValidated(String, String, boolean, boolean, List, String)} was not recognized.
-     */
-    @libcore.api.CorePlatformApi
-    public String getDefaultTimeZoneId() {
-        return defaultTimeZoneId;
-    }
-
-    /**
-     * Qualifier for a country's default time zone. {@code true} indicates whether the default
-     * would be a good choice <em>generally</em> when there's no other information available.
+     * Qualifier for a country's default time zone. {@code true} indicates that the country's
+     * default time zone would be a good choice <em>generally</em> when there's no UTC offset
+     * information available. This will only be {@code true} in countries with multiple zones where
+     * a large majority of the population is covered by only one of them.
      */
     @libcore.api.CorePlatformApi
     public boolean isDefaultTimeZoneBoosted() {
@@ -316,59 +321,15 @@
     }
 
     /**
-     * Returns an immutable, ordered list of time zone mappings for the country in an undefined but
-     * "priority" order, filtered so that only "effective" time zone IDs are returned. An
-     * "effective" time zone is one that differs from another time zone used in the country after
-     * {@code whenMillis}. The list can be empty if there were no zones configured or the configured
-     * zone IDs were not recognized.
-     */
-    @libcore.api.CorePlatformApi
-    public List<TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long whenMillis) {
-        ArrayList<TimeZoneMapping> filteredList = new ArrayList<>(timeZoneMappings.size());
-        for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
-            if (timeZoneMapping.isEffectiveAt(whenMillis)) {
-                filteredList.add(timeZoneMapping);
-            }
-        }
-        return Collections.unmodifiableList(filteredList);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        CountryTimeZones that = (CountryTimeZones) o;
-        return defaultTimeZoneBoosted == that.defaultTimeZoneBoosted
-                && everUsesUtc == that.everUsesUtc
-                && countryIso.equals(that.countryIso)
-                && Objects.equals(defaultTimeZoneId, that.defaultTimeZoneId)
-                && timeZoneMappings.equals(that.timeZoneMappings);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(
-                countryIso, defaultTimeZoneId, defaultTimeZoneBoosted, timeZoneMappings,
-                everUsesUtc);
-    }
-
-    @Override
-    public String toString() {
-        return "CountryTimeZones{"
-                + "countryIso='" + countryIso + '\''
-                + ", defaultTimeZoneId='" + defaultTimeZoneId + '\''
-                + ", defaultTimeZoneBoosted=" + defaultTimeZoneBoosted
-                + ", timeZoneMappings=" + timeZoneMappings
-                + ", everUsesUtc=" + everUsesUtc
-                + '}';
-    }
-
-    /**
-     * Returns true if the country has at least one zone that is the same as UTC at the given time.
+     * Returns {@code true} if the country has at least one time zone that uses UTC at the given
+     * time. This is an efficient check when trying to validate received UTC offset information.
+     * For example, there are situations when a detected zero UTC offset cannot be distinguished
+     * from "no information available" or a corrupted signal. This method is useful because checking
+     * offset information for large countries is relatively expensive but it is generally only the
+     * countries close to the prime meridian that use UTC at <em>any</em> time of the year.
+     *
+     * @param whenMillis the time the offset information is for in milliseconds since the beginning
+     *     of the Unix epoch
      */
     @libcore.api.CorePlatformApi
     public boolean hasUtcZone(long whenMillis) {
@@ -426,6 +387,58 @@
     }
 
     /**
+     * Returns an immutable, ordered list of time zone mappings for the country in an undefined but
+     * "priority" order, filtered so that only "effective" time zone IDs are returned. An
+     * "effective" time zone is one that differs from another time zone used in the country after
+     * {@code whenMillis}. The list can be empty if there were no zones configured or the configured
+     * zone IDs were not recognized.
+     */
+    @libcore.api.CorePlatformApi
+    public List<TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long whenMillis) {
+        ArrayList<TimeZoneMapping> filteredList = new ArrayList<>(timeZoneMappings.size());
+        for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
+            if (timeZoneMapping.isEffectiveAt(whenMillis)) {
+                filteredList.add(timeZoneMapping);
+            }
+        }
+        return Collections.unmodifiableList(filteredList);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        CountryTimeZones that = (CountryTimeZones) o;
+        return defaultTimeZoneBoosted == that.defaultTimeZoneBoosted
+                && everUsesUtc == that.everUsesUtc
+                && countryIso.equals(that.countryIso)
+                && Objects.equals(defaultTimeZoneId, that.defaultTimeZoneId)
+                && timeZoneMappings.equals(that.timeZoneMappings);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                countryIso, defaultTimeZoneId, defaultTimeZoneBoosted, timeZoneMappings,
+                everUsesUtc);
+    }
+
+    @Override
+    public String toString() {
+        return "CountryTimeZones{"
+                + "countryIso='" + countryIso + '\''
+                + ", defaultTimeZoneId='" + defaultTimeZoneId + '\''
+                + ", defaultTimeZoneBoosted=" + defaultTimeZoneBoosted
+                + ", timeZoneMappings=" + timeZoneMappings
+                + ", everUsesUtc=" + everUsesUtc
+                + '}';
+    }
+
+    /**
      * Returns a time zone for the country, if there is one, that matches the supplied properties.
      * If there are multiple matches and the {@code bias} is one of them then it is returned,
      * otherwise an arbitrary match is returned based on the {@link
diff --git a/luni/src/main/java/libcore/timezone/TelephonyNetwork.java b/luni/src/main/java/libcore/timezone/TelephonyNetwork.java
index e0f26ad..3bd1be8 100644
--- a/luni/src/main/java/libcore/timezone/TelephonyNetwork.java
+++ b/luni/src/main/java/libcore/timezone/TelephonyNetwork.java
@@ -87,16 +87,25 @@
         return mccMnc;
     }
 
+    /**
+     * Returns the Mobile Country Code of the network.
+     */
     @libcore.api.CorePlatformApi
     public String getMcc() {
         return mccMnc.mcc;
     }
 
+    /**
+     * Returns the Mobile Network Code of the network.
+     */
     @libcore.api.CorePlatformApi
     public String getMnc() {
         return mccMnc.mnc;
     }
 
+    /**
+     * Returns the country in which the network operates as an ISO 3166 alpha-2 (lower case).
+     */
     @libcore.api.CorePlatformApi
     public String getCountryIsoCode() {
         return countryIsoCode;
diff --git a/luni/src/main/java/libcore/timezone/TelephonyNetworkFinder.java b/luni/src/main/java/libcore/timezone/TelephonyNetworkFinder.java
index f244159..825c06e 100644
--- a/luni/src/main/java/libcore/timezone/TelephonyNetworkFinder.java
+++ b/luni/src/main/java/libcore/timezone/TelephonyNetworkFinder.java
@@ -30,7 +30,8 @@
 import java.util.Set;
 
 /**
- * A class that can find telephony networks loaded via {@link TelephonyLookup}.
+ * A class that can find telephony network information loaded via {@link TelephonyLookup}.
+ *
  * @hide
  */
 @libcore.api.CorePlatformApi
@@ -70,6 +71,11 @@
         this.networksMap = networksMap;
     }
 
+    /**
+     * Returns information held about a specific MCC + MNC combination. It is expected for this
+     * method to return {@code null}. Only known, unusual networks will typically have information
+     * returned, e.g. if they operate in countries other than the one suggested by their MCC.
+     */
     @libcore.api.CorePlatformApi
     public TelephonyNetwork findNetworkByMccMnc(String mcc, String mnc) {
         return networksMap.get(new MccMnc(mcc, mnc));
diff --git a/luni/src/main/java/libcore/timezone/TimeZoneFinder.java b/luni/src/main/java/libcore/timezone/TimeZoneFinder.java
index 3f18e36..274440c 100644
--- a/luni/src/main/java/libcore/timezone/TimeZoneFinder.java
+++ b/luni/src/main/java/libcore/timezone/TimeZoneFinder.java
@@ -199,7 +199,8 @@
     @libcore.api.CorePlatformApi
     public CountryTimeZones lookupCountryTimeZones(String countryIso) {
         synchronized (this) {
-            if (lastCountryTimeZones != null && lastCountryTimeZones.isForCountryCode(countryIso)) {
+            if (lastCountryTimeZones != null
+                    && lastCountryTimeZones.matchesCountryCode(countryIso)) {
                 return lastCountryTimeZones;
             }
         }
@@ -525,5 +526,4 @@
             return validatedCountryTimeZones;
         }
     }
-
 }
diff --git a/luni/src/main/java/libcore/timezone/TzDataSetVersion.java b/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
index 8b97069b..1a1d156 100644
--- a/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
+++ b/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
@@ -25,7 +25,23 @@
 import java.util.regex.Pattern;
 
 /**
- * Constants and logic associated with the time zone data version file.
+ * Version information associated with the set of time zone data on a device.
+ *
+ * <p>Time Zone Data Sets have a major ({@link #getFormatMajorVersion()}) and minor
+ * ({@link #currentFormatMinorVersion()}) version number:
+ * <ul>
+ *   <li>Major version numbers are mutually incompatible. e.g. v2 is not compatible with a v1 or a
+ *   v3 device.</li>
+ *   <li>Minor version numbers are backwards compatible. e.g. a v2.2 data set will work
+ *   on a v2.1 device but not a v2.3 device. The minor version is reset to 1 when the major version
+ *   is incremented.</li>
+ * </ul>
+ *
+ * <p>Data sets contain time zone rules and other data associated wtih a tzdb release
+ * ({@link #getRulesVersion()}) and an additional Android-specific revision number
+ * ({@link #getRevision()}).
+ *
+ * <p>See platform/system/timezone/README.android for more information.
  * @hide
  */
 @libcore.api.CorePlatformApi
@@ -162,22 +178,26 @@
         return readFromFile(new File(tzVersionFileName));
     }
 
+    /** Returns the major version number. See {@link TzDataSetVersion}. */
     @libcore.api.CorePlatformApi
     public int getFormatMajorVersion() {
         return formatMajorVersion;
     }
 
+    /** Returns the minor version number. See {@link TzDataSetVersion}. */
     @libcore.api.CorePlatformApi
     public int getFormatMinorVersion() {
         return formatMinorVersion;
     }
 
+    /** Returns the tzdb version string. See {@link TzDataSetVersion}. */
     @libcore.api.CorePlatformApi
     public String getRulesVersion() {
         return rulesVersion;
     }
 
     // Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797
+    /** Returns the Android revision. See {@link TzDataSetVersion}. */
     @libcore.api.CorePlatformApi
     public int getRevision() {
         return revision;
@@ -210,9 +230,7 @@
         if (o == null || getClass() != o.getClass()) {
             return false;
         }
-
         TzDataSetVersion that = (TzDataSetVersion) o;
-
         if (formatMajorVersion != that.formatMajorVersion) {
             return false;
         }
diff --git a/luni/src/main/java/libcore/timezone/ZoneInfoDb.java b/luni/src/main/java/libcore/timezone/ZoneInfoDb.java
index a94d293..bd41911 100644
--- a/luni/src/main/java/libcore/timezone/ZoneInfoDb.java
+++ b/luni/src/main/java/libcore/timezone/ZoneInfoDb.java
@@ -103,6 +103,9 @@
     }
   };
 
+  /**
+   * Obtains the singleton instance.
+   */
   @libcore.api.CorePlatformApi
   public static ZoneInfoDb getInstance() {
     return DATA;
@@ -349,6 +352,9 @@
     return rawUtcOffsetsCache;
   }
 
+  /**
+   * Returns the tzdb version in use.
+   */
   @libcore.api.CorePlatformApi
   public String getVersion() {
     checkNotClosed();
diff --git a/luni/src/main/native/IcuUtilities.cpp b/luni/src/main/native/IcuUtilities.cpp
index 0db59f9..6811ce5 100644
--- a/luni/src/main/native/IcuUtilities.cpp
+++ b/luni/src/main/native/IcuUtilities.cpp
@@ -16,18 +16,11 @@
 
 #define LOG_TAG "IcuUtilities"
 
-#include <android/log.h>
 #include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
-#include <nativehelper/ScopedUtfChars.h>
 
 #include "IcuUtilities.h"
 
 #include "JniConstants.h"
-#include "JniException.h"
-#include "unicode/strenum.h"
-#include "unicode/ustring.h"
-#include "unicode/uloc.h"
 
 bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error) {
   if (U_SUCCESS(error)) {
diff --git a/luni/src/main/native/JniException.cpp b/luni/src/main/native/JniException.cpp
index 164281d..01346ef 100644
--- a/luni/src/main/native/JniException.cpp
+++ b/luni/src/main/native/JniException.cpp
@@ -19,15 +19,6 @@
 #include "JniException.h"
 #include <nativehelper/JNIHelp.h>
 
-void jniThrowExceptionWithErrno(JNIEnv* env, const char* exceptionClassName, int error) {
-    char buf[BUFSIZ];
-    jniThrowException(env, exceptionClassName, jniStrError(error, buf, sizeof(buf)));
-}
-
 void jniThrowOutOfMemoryError(JNIEnv* env, const char* message) {
     jniThrowException(env, "java/lang/OutOfMemoryError", message);
 }
-
-void jniThrowSocketException(JNIEnv* env, int error) {
-    jniThrowExceptionWithErrno(env, "java/net/SocketException", error);
-}
diff --git a/luni/src/main/native/JniException.h b/luni/src/main/native/JniException.h
index 2d4a097..cff68b8 100644
--- a/luni/src/main/native/JniException.h
+++ b/luni/src/main/native/JniException.h
@@ -19,9 +19,6 @@
 
 #include "jni.h"
 
-void jniThrowExceptionWithErrno(JNIEnv* env, const char* exceptionClassName, int error);
-
 void jniThrowOutOfMemoryError(JNIEnv* env, const char* message);
-void jniThrowSocketException(JNIEnv* env, int error);
 
 #endif  // JNI_EXCEPTION_H_included
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 9879761..aa3d5004 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -17,57 +17,25 @@
 #define LOG_NDEBUG 1
 #define LOG_TAG "ICU"
 
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <string>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-
 #include <memory>
 #include <vector>
 
 #include <androidicuinit/IcuRegistration.h>
 #include <log/log.h>
 #include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
 #include <nativehelper/ScopedStringChars.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <nativehelper/jni_macros.h>
 #include <nativehelper/toStringArray.h>
 
 #include "IcuUtilities.h"
-#include "JniConstants.h"
 #include "JniException.h"
-#include "ScopedIcuLocale.h"
 #include "ScopedIcuULoc.h"
-#include "ScopedJavaUnicodeString.h"
-#include "unicode/brkiter.h"
-#include "unicode/char16ptr.h"
-#include "unicode/calendar.h"
-#include "unicode/datefmt.h"
-#include "unicode/dcfmtsym.h"
-#include "unicode/decimfmt.h"
-#include "unicode/dtfmtsym.h"
-#include "unicode/gregocal.h"
-#include "unicode/locid.h"
-#include "unicode/numfmt.h"
-#include "unicode/strenum.h"
-#include "unicode/ubrk.h"
-#include "unicode/ucal.h"
-#include "unicode/ucasemap.h"
-#include "unicode/ucol.h"
-#include "unicode/ucurr.h"
-#include "unicode/udat.h"
 #include "unicode/udatpg.h"
 #include "unicode/uloc.h"
 #include "unicode/ures.h"
 #include "unicode/ustring.h"
 #include "ureslocs.h"
-#include "valueOf.h"
 
 class ScopedResourceBundle {
  public:
@@ -155,38 +123,6 @@
     return (charCount == 0) ? env->NewStringUTF("XXX") : jniCreateString(env, chars, charCount);
 }
 
-static jstring getCurrencyName(JNIEnv* env, jstring javaLanguageTag, jstring javaCurrencyCode, UCurrNameStyle nameStyle) {
-  ScopedUtfChars languageTag(env, javaLanguageTag);
-  if (languageTag.c_str() == NULL) {
-    return NULL;
-  }
-  ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
-  if (!currencyCode.valid()) {
-    return NULL;
-  }
-  icu::UnicodeString icuCurrencyCode(currencyCode.unicodeString());
-  UErrorCode status = U_ZERO_ERROR;
-  UBool isChoiceFormat = false;
-  int32_t charCount;
-  const UChar* chars = ucurr_getName(icuCurrencyCode.getTerminatedBuffer(), languageTag.c_str(),
-                                     nameStyle, &isChoiceFormat, &charCount, &status);
-  if (status == U_USING_DEFAULT_WARNING) {
-    if (nameStyle == UCURR_SYMBOL_NAME) {
-      // ICU doesn't distinguish between falling back to the root locale and meeting a genuinely
-      // unknown currency. The Currency class does.
-      if (!ucurr_isAvailable(icuCurrencyCode.getTerminatedBuffer(), U_DATE_MIN, U_DATE_MAX, &status)) {
-        return NULL;
-      }
-    }
-    if (nameStyle == UCURR_LONG_NAME) {
-      // ICU's default is English. We want the ISO 4217 currency code instead.
-      chars = icuCurrencyCode.getBuffer();
-      charCount = icuCurrencyCode.length();
-    }
-  }
-  return (charCount == 0) ? NULL : jniCreateString(env, chars, charCount);
-}
-
 static jstring ICU_getISO3Country(JNIEnv* env, jclass, jstring javaLanguageTag) {
   ScopedIcuULoc icuLocale(env, javaLanguageTag);
   if (!icuLocale.valid()) {
@@ -215,378 +151,6 @@
     return toStringArray(env, uloc_countAvailable, uloc_getAvailable);
 }
 
-static bool setIntegerField(JNIEnv* env, jobject obj, const char* fieldName, int value) {
-    ScopedLocalRef<jobject> integerValue(env, integerValueOf(env, value));
-    if (integerValue.get() == NULL) return false;
-    jfieldID fid = env->GetFieldID(JniConstants::GetLocaleDataClass(env), fieldName, "Ljava/lang/Integer;");
-    env->SetObjectField(obj, fid, integerValue.get());
-    return true;
-}
-
-static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, jstring value) {
-    jfieldID fid = env->GetFieldID(JniConstants::GetLocaleDataClass(env), fieldName, "Ljava/lang/String;");
-    env->SetObjectField(obj, fid, value);
-    env->DeleteLocalRef(value);
-}
-
-static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, jobjectArray value) {
-    jfieldID fid = env->GetFieldID(JniConstants::GetLocaleDataClass(env), fieldName, "[Ljava/lang/String;");
-    env->SetObjectField(obj, fid, value);
-}
-
-static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString* valueArray, int32_t size) {
-    ScopedLocalRef<jobjectArray> result(env, env->NewObjectArray(size, JniConstants::GetStringClass(env), NULL));
-    for (int32_t i = 0; i < size ; i++) {
-        ScopedLocalRef<jstring> s(env, jniCreateString(env, valueArray[i].getBuffer(),valueArray[i].length()));
-        if (env->ExceptionCheck()) {
-            return;
-        }
-        env->SetObjectArrayElement(result.get(), i, s.get());
-        if (env->ExceptionCheck()) {
-            return;
-        }
-    }
-    setStringArrayField(env, obj, fieldName, result.get());
-}
-
-static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, UResourceBundle* bundle, int index) {
-  UErrorCode status = U_ZERO_ERROR;
-  int charCount;
-  const UChar* chars;
-  UResourceBundle* currentBundle = ures_getByIndex(bundle, index, NULL, &status);
-  switch (ures_getType(currentBundle)) {
-      case URES_STRING:
-         chars = ures_getString(currentBundle, &charCount, &status);
-         break;
-      case URES_ARRAY:
-         // In case there is an array, Android currently only cares about the
-         // first string of that array, the rest of the array is used by ICU
-         // for additional data ignored by Android.
-         chars = ures_getStringByIndex(currentBundle, 0, &charCount, &status);
-         break;
-      default:
-         status = U_INVALID_FORMAT_ERROR;
-  }
-  ures_close(currentBundle);
-  if (U_SUCCESS(status)) {
-    setStringField(env, obj, fieldName, jniCreateString(env, chars, charCount));
-  } else {
-    ALOGE("Error setting String field %s from ICU resource (index %d): %s", fieldName, index, u_errorName(status));
-  }
-}
-
-static void setCharField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString& value) {
-    if (value.length() == 0) {
-        return;
-    }
-    jfieldID fid = env->GetFieldID(JniConstants::GetLocaleDataClass(env), fieldName, "C");
-    env->SetCharField(obj, fid, value.charAt(0));
-}
-
-static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString& value) {
-    const UChar* chars = value.getBuffer();
-    setStringField(env, obj, fieldName, jniCreateString(env, chars, value.length()));
-}
-
-static void setNumberPatterns(JNIEnv* env, jobject obj, icu::Locale& locale) {
-    UErrorCode status = U_ZERO_ERROR;
-
-    icu::UnicodeString pattern;
-    std::unique_ptr<icu::DecimalFormat> fmt(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_CURRENCY, status)));
-    pattern = fmt->toPattern(pattern.remove());
-    setStringField(env, obj, "currencyPattern", pattern);
-
-    fmt.reset(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_DECIMAL, status)));
-    pattern = fmt->toPattern(pattern.remove());
-    setStringField(env, obj, "numberPattern", pattern);
-
-    fmt.reset(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_PERCENT, status)));
-    pattern = fmt->toPattern(pattern.remove());
-    setStringField(env, obj, "percentPattern", pattern);
-}
-
-static void setDecimalFormatSymbolsData(JNIEnv* env, jobject obj, icu::Locale& locale) {
-    UErrorCode status = U_ZERO_ERROR;
-    icu::DecimalFormatSymbols dfs(locale, status);
-
-    setCharField(env, obj, "decimalSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kDecimalSeparatorSymbol));
-    setCharField(env, obj, "groupingSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kGroupingSeparatorSymbol));
-    setCharField(env, obj, "patternSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kPatternSeparatorSymbol));
-    setStringField(env, obj, "percent", dfs.getSymbol(icu::DecimalFormatSymbols::kPercentSymbol));
-    setStringField(env, obj, "perMill", dfs.getSymbol(icu::DecimalFormatSymbols::kPerMillSymbol));
-    setCharField(env, obj, "monetarySeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kMonetarySeparatorSymbol));
-    setStringField(env, obj, "minusSign", dfs.getSymbol(icu::DecimalFormatSymbols:: kMinusSignSymbol));
-    setStringField(env, obj, "exponentSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kExponentialSymbol));
-    setStringField(env, obj, "infinity", dfs.getSymbol(icu::DecimalFormatSymbols::kInfinitySymbol));
-    setStringField(env, obj, "NaN", dfs.getSymbol(icu::DecimalFormatSymbols::kNaNSymbol));
-    setCharField(env, obj, "zeroDigit", dfs.getSymbol(icu::DecimalFormatSymbols::kZeroDigitSymbol));
-}
-
-
-// Iterates up through the locale hierarchy. So "en_US" would return "en_US", "en", "".
-class LocaleNameIterator {
- public:
-  LocaleNameIterator(const char* locale_name, UErrorCode& status) : status_(status), has_next_(true) {
-    strcpy(locale_name_, locale_name);
-    locale_name_length_ = strlen(locale_name_);
-  }
-
-  const char* Get() {
-      return locale_name_;
-  }
-
-  bool HasNext() {
-    return has_next_;
-  }
-
-  void Up() {
-    if (locale_name_length_ == 0) {
-      has_next_ = false;
-    } else {
-      locale_name_length_ = uloc_getParent(locale_name_, locale_name_, sizeof(locale_name_), &status_);
-    }
-  }
-
- private:
-  UErrorCode& status_;
-  bool has_next_;
-  char locale_name_[ULOC_FULLNAME_CAPACITY];
-  int32_t locale_name_length_;
-
-  DISALLOW_COPY_AND_ASSIGN(LocaleNameIterator);
-};
-
-static bool getAmPmMarkersNarrow(JNIEnv* env, jobject localeData, const char* locale_name) {
-  UErrorCode status = U_ZERO_ERROR;
-  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
-  if (U_FAILURE(status)) {
-    return false;
-  }
-  ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
-  if (U_FAILURE(status)) {
-    return false;
-  }
-  ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
-  if (U_FAILURE(status)) {
-    return false;
-  }
-  ScopedResourceBundle amPmMarkersNarrow(ures_getByKey(gregorian.get(), "AmPmMarkersNarrow", NULL, &status));
-  if (U_FAILURE(status)) {
-    return false;
-  }
-  setStringField(env, localeData, "narrowAm", amPmMarkersNarrow.get(), 0);
-  setStringField(env, localeData, "narrowPm", amPmMarkersNarrow.get(), 1);
-  return true;
-}
-
-static bool getDateTimePatterns(JNIEnv* env, jobject localeData, const char* locale_name) {
-  UErrorCode status = U_ZERO_ERROR;
-  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
-  if (U_FAILURE(status)) {
-    return false;
-  }
-  ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
-  if (U_FAILURE(status)) {
-    return false;
-  }
-  ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
-  if (U_FAILURE(status)) {
-    return false;
-  }
-  ScopedResourceBundle dateTimePatterns(ures_getByKey(gregorian.get(), "DateTimePatterns", NULL, &status));
-  if (U_FAILURE(status)) {
-    return false;
-  }
-  setStringField(env, localeData, "fullTimeFormat", dateTimePatterns.get(), 0);
-  setStringField(env, localeData, "longTimeFormat", dateTimePatterns.get(), 1);
-  setStringField(env, localeData, "mediumTimeFormat", dateTimePatterns.get(), 2);
-  setStringField(env, localeData, "shortTimeFormat", dateTimePatterns.get(), 3);
-  setStringField(env, localeData, "fullDateFormat", dateTimePatterns.get(), 4);
-  setStringField(env, localeData, "longDateFormat", dateTimePatterns.get(), 5);
-  setStringField(env, localeData, "mediumDateFormat", dateTimePatterns.get(), 6);
-  setStringField(env, localeData, "shortDateFormat", dateTimePatterns.get(), 7);
-  return true;
-}
-
-static bool getYesterdayTodayAndTomorrow(JNIEnv* env, jobject localeData, const icu::Locale& locale, const char* locale_name) {
-  UErrorCode status = U_ZERO_ERROR;
-  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
-  ScopedResourceBundle fields(ures_getByKey(root.get(), "fields", NULL, &status));
-  ScopedResourceBundle day(ures_getByKey(fields.get(), "day", NULL, &status));
-  ScopedResourceBundle relative(ures_getByKey(day.get(), "relative", NULL, &status));
-  if (U_FAILURE(status)) {
-    return false;
-  }
-
-  icu::UnicodeString yesterday(icu::ures_getUnicodeStringByKey(relative.get(), "-1", &status));
-  icu::UnicodeString today(icu::ures_getUnicodeStringByKey(relative.get(), "0", &status));
-  icu::UnicodeString tomorrow(icu::ures_getUnicodeStringByKey(relative.get(), "1", &status));
-  if (U_FAILURE(status)) {
-    ALOGE("Error getting yesterday/today/tomorrow for %s: %s", locale_name, u_errorName(status));
-    return false;
-  }
-
-  // We title-case the strings so they have consistent capitalization (http://b/14493853).
-  std::unique_ptr<icu::BreakIterator> brk(icu::BreakIterator::createSentenceInstance(locale, status));
-  if (U_FAILURE(status)) {
-    ALOGE("Error getting yesterday/today/tomorrow break iterator for %s: %s", locale_name, u_errorName(status));
-    return false;
-  }
-  yesterday.toTitle(brk.get(), locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
-  today.toTitle(brk.get(), locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
-  tomorrow.toTitle(brk.get(), locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
-
-  setStringField(env, localeData, "yesterday", yesterday);
-  setStringField(env, localeData, "today", today);
-  setStringField(env, localeData, "tomorrow", tomorrow);
-  return true;
-}
-
-static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLanguageTag, jobject localeData) {
-    ScopedUtfChars languageTag(env, javaLanguageTag);
-    if (languageTag.c_str() == NULL) {
-        return JNI_FALSE;
-    }
-    if (languageTag.size() >= ULOC_FULLNAME_CAPACITY) {
-        return JNI_FALSE; // ICU has a fixed-length limit.
-    }
-
-    ScopedIcuLocale icuLocale(env, javaLanguageTag);
-    if (!icuLocale.valid()) {
-      return JNI_FALSE;
-    }
-
-    // Get the DateTimePatterns.
-    UErrorCode status = U_ZERO_ERROR;
-    bool foundDateTimePatterns = false;
-    for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
-      if (getDateTimePatterns(env, localeData, it.Get())) {
-          foundDateTimePatterns = true;
-          break;
-      }
-    }
-    if (!foundDateTimePatterns) {
-        ALOGE("Couldn't find ICU DateTimePatterns for %s", languageTag.c_str());
-        return JNI_FALSE;
-    }
-
-    // Get the "Yesterday", "Today", and "Tomorrow" strings.
-    bool foundYesterdayTodayAndTomorrow = false;
-    for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
-      if (getYesterdayTodayAndTomorrow(env, localeData, icuLocale.locale(), it.Get())) {
-        foundYesterdayTodayAndTomorrow = true;
-        break;
-      }
-    }
-    if (!foundYesterdayTodayAndTomorrow) {
-      ALOGE("Couldn't find ICU yesterday/today/tomorrow for %s", languageTag.c_str());
-      return JNI_FALSE;
-    }
-
-    // Get the narrow "AM" and "PM" strings.
-    bool foundAmPmMarkersNarrow = false;
-    for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
-      if (getAmPmMarkersNarrow(env, localeData, it.Get())) {
-        foundAmPmMarkersNarrow = true;
-        break;
-      }
-    }
-    if (!foundAmPmMarkersNarrow) {
-      ALOGE("Couldn't find ICU AmPmMarkersNarrow for %s", languageTag.c_str());
-      return JNI_FALSE;
-    }
-
-    status = U_ZERO_ERROR;
-    std::unique_ptr<icu::Calendar> cal(icu::Calendar::createInstance(icuLocale.locale(), status));
-    if (U_FAILURE(status)) {
-        return JNI_FALSE;
-    }
-    if (!setIntegerField(env, localeData, "firstDayOfWeek", cal->getFirstDayOfWeek())) {
-      return JNI_FALSE;
-    }
-    if (!setIntegerField(env, localeData, "minimalDaysInFirstWeek", cal->getMinimalDaysInFirstWeek())) {
-      return JNI_FALSE;
-    }
-
-    // Get DateFormatSymbols.
-    status = U_ZERO_ERROR;
-    icu::DateFormatSymbols dateFormatSym(icuLocale.locale(), status);
-    if (U_FAILURE(status)) {
-        return JNI_FALSE;
-    }
-
-    // Get AM/PM and BC/AD.
-    int32_t count = 0;
-    const icu::UnicodeString* amPmStrs = dateFormatSym.getAmPmStrings(count);
-    setStringArrayField(env, localeData, "amPm", amPmStrs, count);
-    const icu::UnicodeString* erasStrs = dateFormatSym.getEras(count);
-    setStringArrayField(env, localeData, "eras", erasStrs, count);
-
-    const icu::UnicodeString* longMonthNames =
-       dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::WIDE);
-    setStringArrayField(env, localeData, "longMonthNames", longMonthNames, count);
-    const icu::UnicodeString* shortMonthNames =
-        dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::ABBREVIATED);
-    setStringArrayField(env, localeData, "shortMonthNames", shortMonthNames, count);
-    const icu::UnicodeString* tinyMonthNames =
-        dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::NARROW);
-    setStringArrayField(env, localeData, "tinyMonthNames", tinyMonthNames, count);
-    const icu::UnicodeString* longWeekdayNames =
-        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::WIDE);
-    setStringArrayField(env, localeData, "longWeekdayNames", longWeekdayNames, count);
-    const icu::UnicodeString* shortWeekdayNames =
-        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::ABBREVIATED);
-    setStringArrayField(env, localeData, "shortWeekdayNames", shortWeekdayNames, count);
-    const icu::UnicodeString* tinyWeekdayNames =
-        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::NARROW);
-    setStringArrayField(env, localeData, "tinyWeekdayNames", tinyWeekdayNames, count);
-
-    const icu::UnicodeString* longStandAloneMonthNames =
-        dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::WIDE);
-    setStringArrayField(env, localeData, "longStandAloneMonthNames", longStandAloneMonthNames, count);
-    const icu::UnicodeString* shortStandAloneMonthNames =
-        dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::ABBREVIATED);
-    setStringArrayField(env, localeData, "shortStandAloneMonthNames", shortStandAloneMonthNames, count);
-    const icu::UnicodeString* tinyStandAloneMonthNames =
-        dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::NARROW);
-    setStringArrayField(env, localeData, "tinyStandAloneMonthNames", tinyStandAloneMonthNames, count);
-    const icu::UnicodeString* longStandAloneWeekdayNames =
-        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::WIDE);
-    setStringArrayField(env, localeData, "longStandAloneWeekdayNames", longStandAloneWeekdayNames, count);
-    const icu::UnicodeString* shortStandAloneWeekdayNames =
-        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::ABBREVIATED);
-    setStringArrayField(env, localeData, "shortStandAloneWeekdayNames", shortStandAloneWeekdayNames, count);
-    const icu::UnicodeString* tinyStandAloneWeekdayNames =
-        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::NARROW);
-    setStringArrayField(env, localeData, "tinyStandAloneWeekdayNames", tinyStandAloneWeekdayNames, count);
-
-    status = U_ZERO_ERROR;
-
-    // For numberPatterns and symbols.
-    setNumberPatterns(env, localeData, icuLocale.locale());
-    setDecimalFormatSymbolsData(env, localeData, icuLocale.locale());
-
-    jstring countryCode = env->NewStringUTF(icuLocale.locale().getCountry());
-    jstring internationalCurrencySymbol = ICU_getCurrencyCode(env, NULL, countryCode);
-    env->DeleteLocalRef(countryCode);
-    countryCode = NULL;
-
-    jstring currencySymbol = NULL;
-    if (internationalCurrencySymbol != NULL) {
-        currencySymbol = getCurrencyName(env, javaLanguageTag, internationalCurrencySymbol, UCURR_SYMBOL_NAME);
-    } else {
-        internationalCurrencySymbol = env->NewStringUTF("XXX");
-    }
-    if (currencySymbol == NULL) {
-        // This is the UTF-8 encoding of U+00A4 (CURRENCY SIGN).
-        currencySymbol = env->NewStringUTF("\xc2\xa4");
-    }
-    setStringField(env, localeData, "currencySymbol", currencySymbol);
-    setStringField(env, localeData, "internationalCurrencySymbol", internationalCurrencySymbol);
-
-    return JNI_TRUE;
-}
-
 static jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLanguageTag) {
   ScopedIcuULoc icuLocale(env, javaLanguageTag);
   if (!icuLocale.valid()) {
@@ -661,7 +225,6 @@
     NATIVE_METHOD(ICU, getISOCountriesNative, "()[Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getISOLanguagesNative, "()[Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getScript, "(Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, initLocaleDataNative, "(Ljava/lang/String;Llibcore/icu/LocaleData;)Z"),
     NATIVE_METHOD(ICU, setDefaultLocale, "(Ljava/lang/String;)V"),
 };
 
diff --git a/luni/src/main/native/libcore_io_Linux.cpp b/luni/src/main/native/libcore_io_Linux.cpp
index 9e44e63..a99b862 100644
--- a/luni/src/main/native/libcore_io_Linux.cpp
+++ b/luni/src/main/native/libcore_io_Linux.cpp
@@ -29,6 +29,7 @@
 #include <pwd.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/capability.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
@@ -2470,7 +2471,7 @@
 
 static jstring Linux_strerror(JNIEnv* env, jobject, jint errnum) {
     char buffer[BUFSIZ];
-    const char* message = jniStrError(errnum, buffer, sizeof(buffer));
+    const char* message = strerror_r(errnum, buffer, sizeof(buffer));
     return env->NewStringUTF(message);
 }
 
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/lang/OldClassTest.java b/luni/src/test/java/libcore/java/lang/OldClassTest.java
index f5bc787..e0955bc 100644
--- a/luni/src/test/java/libcore/java/lang/OldClassTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldClassTest.java
@@ -306,7 +306,7 @@
         }
     }
 
-    // AndroidOnly: Class.forName method throws ClassNotFoundException on Android.
+    // Android-note: Class.forName method throws ClassNotFoundException on Android.
     public void test_forNameLjava_lang_StringLbooleanLClassLoader_AndroidOnly() throws Exception {
 
         // Android doesn't support loading class files from a jar.
@@ -460,7 +460,7 @@
         assertEquals(AbstractList.class, type.getRawType());
     }
 
-    // AndroidOnly: Uses dalvik.system.PathClassLoader.
+    // Android-note: Uses dalvik.system.PathClassLoader.
     // Different behavior between cts host and run-core-test")
     public void test_getPackage() {
 
diff --git a/luni/src/test/java/libcore/java/lang/SystemTest.java b/luni/src/test/java/libcore/java/lang/SystemTest.java
index 56b6558..939a9f3 100644
--- a/luni/src/test/java/libcore/java/lang/SystemTest.java
+++ b/luni/src/test/java/libcore/java/lang/SystemTest.java
@@ -160,7 +160,7 @@
     }
 
     public void testSystemProperties_immutable() {
-        // Android-specific: The RI does not have a concept of immutable properties.
+        // Android-note: The RI does not have a concept of immutable properties.
 
         // user.dir is an immutable property
         String userDir = System.getProperty("user.dir");
@@ -223,10 +223,10 @@
 
         System.setProperties(newProperties);
 
-        // Android-specific: The RI makes the setProperties() argument the system properties object,
+        // Android-note: The RI makes the setProperties() argument the system properties object.
         // Android makes a new Properties object and copies the properties.
         assertNotSame(newProperties, System.getProperties());
-        // Android-specific: The RI does not have a concept of immutable properties.
+        // Android-note: The RI does not have a concept of immutable properties.
         assertEquals(userDir, System.getProperty("user.dir"));
 
         assertEquals("v2", System.getProperty("p1"));
@@ -242,7 +242,7 @@
 
         properties.clear();
 
-        // Android-specific: The RI clears everything, Android resets to immutable defaults.
+        // Android-note: The RI clears everything, Android resets to immutable defaults.
         assertEquals(userDir, System.getProperty("user.dir"));
         assertNull(System.getProperty("p1"));
     }
diff --git a/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java b/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java
index eb3f4ca..75344af 100644
--- a/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java
+++ b/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java
@@ -35,7 +35,7 @@
         format = (DecimalFormat) NumberFormat.getNumberInstance();
     }
 
-    // AndroidOnly: special feature of icu4c
+    // Android-note: special feature of icu4c.
     public void test_sigDigitPatterns() throws Exception {
         DecimalFormat format = (DecimalFormat) NumberFormat
         .getInstance(Locale.US);
@@ -62,7 +62,7 @@
         }
     }
 
-    // AndroidOnly: special feature of icu4c
+    // Android-note: special feature of icu4c.
     public void test_paddingPattern() throws Exception {
         format.applyPattern("*x##,##,#,##0.0#");
         assertEquals("xxxxxxxxx123.0", format.format(123));
@@ -95,7 +95,7 @@
         }
     }
 
-    // AndroidOnly: special feature of icu4c
+    // Android-note: special feature of icu4c.
     public void test_positiveExponentSign() throws Exception {
         format.applyPattern("0.###E+0");
         assertEquals("1E+2", format.format(100));
@@ -124,7 +124,7 @@
         }
     }
 
-    // AndroidOnly: special feature of icu4c
+    // Android-note: special feature of icu4c.
     public void test_secondaryGroupingSize() throws Exception {
         format.applyPattern("#,##,###,####");
         assertEquals("123,456,7890", format.format(1234567890));
diff --git a/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java b/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java
index 607397d..42caf13 100644
--- a/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java
+++ b/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java
@@ -16,16 +16,21 @@
 
 package libcore.libcore.icu;
 
+import static org.junit.Assert.assertArrayEquals;
+
 import java.util.Locale;
 import libcore.icu.LocaleData;
 
 public class LocaleDataTest extends junit.framework.TestCase {
+  static {
+    System.loadLibrary("javacoretests");
+  }
+
   public void testAll() throws Exception {
     // Test that we can get the locale data for all known locales.
     for (Locale l : Locale.getAvailableLocales()) {
       LocaleData d = LocaleData.get(l);
-      // System.err.format("%20s %s %s %s\n", l, d.yesterday, d.today, d.tomorrow);
-      // System.err.format("%20s %10s %10s\n", l, d.timeFormat_hm, d.timeFormat_Hm);
+      System.err.format("%20s %10s %10s\n", l, d.timeFormat_hm, d.timeFormat_Hm);
     }
   }
 
@@ -52,17 +57,6 @@
     assertEquals("Sun", l.shortStandAloneWeekdayNames[1]);
     assertEquals("S", l.tinyStandAloneWeekdayNames[1]);
 
-    assertEquals("Yesterday", l.yesterday);
-    assertEquals("Today", l.today);
-    assertEquals("Tomorrow", l.tomorrow);
-  }
-
-  public void test_de_DE() throws Exception {
-    LocaleData l = LocaleData.get(new Locale("de", "DE"));
-
-    assertEquals("Gestern", l.yesterday);
-    assertEquals("Heute", l.today);
-    assertEquals("Morgen", l.tomorrow);
   }
 
   public void test_cs_CZ() throws Exception {
@@ -77,15 +71,6 @@
     assertEquals("1", l.tinyStandAloneMonthNames[0]);
   }
 
-  public void test_ko_KR() throws Exception {
-    LocaleData l = LocaleData.get(new Locale("ko", "KR"));
-
-    // Ensure the fix for http://b/14493853 doesn't mangle Hangul.
-    assertEquals("어제", l.yesterday);
-    assertEquals("오늘", l.today);
-    assertEquals("내일", l.tomorrow);
-  }
-
   public void test_ru_RU() throws Exception {
     LocaleData l = LocaleData.get(new Locale("ru", "RU"));
 
@@ -146,4 +131,157 @@
   public void testInvalidLocale() {
     LocaleData.get(new Locale("invalidLocale"));
   }
+
+  // BCP 47 language tags.
+  private static final String[] TEST_LANGUAGE_TAGS = new String[] {
+    "en-US",
+    "en-GB",
+    "ar-EG",
+    "zh-CN",
+    "zh-TW",
+    "nl-NL",
+    "fr-FR",
+    "de-DE",
+    "it-IT",
+    "ja-JP",
+    "ko-KR",
+    "pl-PL",
+    "pt-BR",
+    "ru-RU",
+    "es-ES",
+    "th-TH",
+    "tr-TR",
+    "es-419",
+  };
+
+  public void testInitLocaleData_icu4cConsistency() throws Exception {
+    // Don't test all available locales due to incorrect assumptions in the JNI test code
+    // calling ICU4C. The JNI test code came from libcore, but now moved into this test to load
+    // the locale data from ICU4C. The inappropriate assumptions are the below
+    // 1. Use uloc_getParent as fallback locale in ICU resource bundle format.
+    //    uloc_getParent only truncates the locale ID string tp get parent, but doesn't use the
+    //    parent-child relationships in the locale data.
+    // 2. Truncate single Unicode character, e.g. U+11136 CHAKMA DIGIT ZERO, into single high
+    //    surrogate, e.g. 0xD804.
+    // 3. Does not consider alias in Root Locale
+    //    For AM/PM markers, AmPmMarkersNarrow is specified in the Root Locale as the alias of
+    //    "/LOCALE/calendar/gregorian/AmPmMarkersAbbr".
+
+    for (String languageTag : TEST_LANGUAGE_TAGS) {
+      Locale locale = Locale.forLanguageTag(languageTag);
+      LocaleData localeData = LocaleData.initLocaleData(locale);
+      Icu4cLocaleData testData = new Icu4cLocaleData();
+      assertTrue("Failed to load ICU4C data", initIcu4cLocaleData(locale.toLanguageTag(),
+        testData, Icu4cLocaleData.class));
+      assertLocaleDataEquals(locale, testData, localeData);
+    }
+  }
+
+  /**
+   * This function does not compare all fields in {@code Icu4cLocaleData} and {@code LocaleData}
+   * because some fields, e.g. patternSeparator, in {@Code LocaleData} has always implemented
+   * by ICU4J or always by ICU4C.
+   */
+  private static void assertLocaleDataEquals(Locale locale, Icu4cLocaleData testData,
+      LocaleData localeData) {
+    String baseMsg = "LocaleData provides different value in locale " + locale + " in the field:";
+    assertEquals(baseMsg + "minimalDaysInFirstWeek", testData.firstDayOfWeek, localeData.firstDayOfWeek);
+    assertEquals(baseMsg + "minimalDaysInFirstWeek", testData.minimalDaysInFirstWeek, localeData.minimalDaysInFirstWeek);
+    assertArrayEquals(baseMsg + "amPm", testData.amPm, localeData.amPm);
+    assertArrayEquals(baseMsg + "eras", testData.eras, localeData.eras);
+    assertArrayEquals(baseMsg + "longMonthNames", testData.longMonthNames, localeData.longMonthNames);
+    assertArrayEquals(baseMsg + "shortMonthNames", testData.shortMonthNames, localeData.shortMonthNames);
+    assertArrayEquals(baseMsg + "tinyMonthNames", testData.tinyMonthNames, localeData.tinyMonthNames);
+    assertArrayEquals(baseMsg + "longStandAloneMonthNames", testData.longStandAloneMonthNames, localeData.longStandAloneMonthNames);
+    assertArrayEquals(baseMsg + "shortStandAloneMonthNames", testData.shortStandAloneMonthNames, localeData.shortStandAloneMonthNames);
+    assertArrayEquals(baseMsg + "tinyStandAloneMonthNames", testData.tinyStandAloneMonthNames, localeData.tinyStandAloneMonthNames);
+    assertArrayEquals(baseMsg + "longWeekdayNames", testData.longWeekdayNames, localeData.longWeekdayNames);
+    assertArrayEquals(baseMsg + "shortWeekdayNames", testData.shortWeekdayNames, localeData.shortWeekdayNames);
+    assertArrayEquals(baseMsg + "tinyWeekdayNames", testData.tinyWeekdayNames, localeData.tinyWeekdayNames);
+    assertArrayEquals(baseMsg + "longStandAloneWeekdayNames", testData.longStandAloneWeekdayNames, localeData.longStandAloneWeekdayNames);
+    assertArrayEquals(baseMsg + "shortStandAloneWeekdayNames", testData.shortStandAloneWeekdayNames, localeData.shortStandAloneWeekdayNames);
+    assertArrayEquals(baseMsg + "tinyStandAloneWeekdayNames", testData.tinyStandAloneWeekdayNames, localeData.tinyStandAloneWeekdayNames);
+
+    assertEquals(baseMsg + "fullTimeFormat", testData.fullTimeFormat, localeData.fullTimeFormat);
+    assertEquals(baseMsg + "longTimeFormat", testData.longTimeFormat, localeData.longTimeFormat);
+    assertEquals(baseMsg + "mediumTimeFormat", testData.mediumTimeFormat, localeData.mediumTimeFormat);
+    assertEquals(baseMsg + "shortTimeFormat", testData.shortTimeFormat, localeData.shortTimeFormat);
+    assertEquals(baseMsg + "fullDateFormat", testData.fullDateFormat, localeData.fullDateFormat);
+    assertEquals(baseMsg + "longDateFormat", testData.longDateFormat, localeData.longDateFormat);
+    assertEquals(baseMsg + "mediumDateFormat", testData.mediumDateFormat, localeData.mediumDateFormat);
+    assertEquals(baseMsg + "shortDateFormat", testData.shortDateFormat, localeData.shortDateFormat);
+    assertEquals(baseMsg + "narrowAm", testData.narrowAm, localeData.narrowAm);
+    assertEquals(baseMsg + "narrowPm", testData.narrowPm, localeData.narrowPm);
+
+    assertEquals(baseMsg + "zeroDigit", testData.zeroDigit, localeData.zeroDigit);
+    assertEquals(baseMsg + "decimalSeparator", testData.decimalSeparator, localeData.decimalSeparator);
+    assertEquals(baseMsg + "groupingSeparator", testData.groupingSeparator, localeData.groupingSeparator);
+    assertEquals(baseMsg + "percent", testData.percent, localeData.percent);
+    assertEquals(baseMsg + "perMill", testData.perMill, localeData.perMill);
+    assertEquals(baseMsg + "monetarySeparator", testData.monetarySeparator, localeData.monetarySeparator);
+    assertEquals(baseMsg + "minusSign", testData.minusSign, localeData.minusSign);
+    assertEquals(baseMsg + "exponentSeparator", testData.exponentSeparator, localeData.exponentSeparator);
+    assertEquals(baseMsg + "infinity", testData.infinity, localeData.infinity);
+    assertEquals(baseMsg + "NaN", testData.NaN, localeData.NaN);
+    assertEquals(baseMsg + "numberPattern", testData.numberPattern, localeData.numberPattern);
+    assertEquals(baseMsg + "currencyPattern", testData.currencyPattern, localeData.currencyPattern);
+    assertEquals(baseMsg + "percentPattern", testData.percentPattern, localeData.percentPattern);
+  }
+
+  private static native boolean initIcu4cLocaleData(String languageTag,
+    Icu4cLocaleData icu4cLocaleData, Class<Icu4cLocaleData> Icu4cLocaleData);
+
+  private static class Icu4cLocaleData {
+      public Integer firstDayOfWeek;
+      public Integer minimalDaysInFirstWeek;
+
+      public String[] amPm; // "AM", "PM".
+      public String[] eras; // "BC", "AD".
+      public String[] longMonthNames; // "January", ...
+      public String[] shortMonthNames; // "Jan", ...
+      public String[] tinyMonthNames; // "J", ...
+      public String[] longStandAloneMonthNames; // "January", ...
+      public String[] shortStandAloneMonthNames; // "Jan", ...
+      public String[] tinyStandAloneMonthNames; // "J", ...
+      public String[] longWeekdayNames; // "Sunday", ...
+      public String[] shortWeekdayNames; // "Sun", ...
+      public String[] tinyWeekdayNames; // "S", ...
+      public String[] longStandAloneWeekdayNames; // "Sunday", ...
+      public String[] shortStandAloneWeekdayNames; // "Sun", ...
+      public String[] tinyStandAloneWeekdayNames; // "S", ...
+
+      public String fullTimeFormat;
+      public String longTimeFormat;
+      public String mediumTimeFormat;
+      public String shortTimeFormat;
+
+      public String fullDateFormat;
+      public String longDateFormat;
+      public String mediumDateFormat;
+      public String shortDateFormat;
+
+      // Used by TimePicker. Not currently used by UTS#35.
+      public String narrowAm; // "a".
+      public String narrowPm; // "p".
+
+      // Used by DecimalFormatSymbols.
+      public char zeroDigit;
+      public char decimalSeparator;
+      public char groupingSeparator;
+      public char patternSeparator;
+      public String percent;
+      public String perMill;
+      public char monetarySeparator;
+      public String minusSign;
+      public String exponentSeparator;
+      public String infinity;
+      public String NaN;
+
+      // Used by DecimalFormat and NumberFormat.
+      public String numberPattern;
+      public String currencyPattern;
+      public String percentPattern;
+
+      private Icu4cLocaleData() {}
+  }
 }
diff --git a/luni/src/test/java/libcore/libcore/timezone/CountryTimeZonesTest.java b/luni/src/test/java/libcore/libcore/timezone/CountryTimeZonesTest.java
index cf32896..3fbd0fe 100644
--- a/luni/src/test/java/libcore/libcore/timezone/CountryTimeZonesTest.java
+++ b/luni/src/test/java/libcore/libcore/timezone/CountryTimeZonesTest.java
@@ -74,7 +74,7 @@
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
                 "gb", "Europe/London", false /* defaultTimeZoneBoost */,
                 true /* everUsesUtc */, timeZoneMappings("Europe/London"), "test");
-        assertTrue(countryTimeZones.isForCountryCode("gb"));
+        assertTrue(countryTimeZones.matchesCountryCode("gb"));
         assertEquals("Europe/London", countryTimeZones.getDefaultTimeZoneId());
         assertZoneEquals(zone("Europe/London"), countryTimeZones.getDefaultTimeZone());
         assertEquals(timeZoneMappings("Europe/London"), countryTimeZones.getTimeZoneMappings());
@@ -114,13 +114,13 @@
     }
 
     @Test
-    public void isForCountryCode() throws Exception {
+    public void matchesCountryCode() throws Exception {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
                 "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
                 timeZoneMappings("Europe/London"), "test");
-        assertTrue(countryTimeZones.isForCountryCode("GB"));
-        assertTrue(countryTimeZones.isForCountryCode("Gb"));
-        assertTrue(countryTimeZones.isForCountryCode("gB"));
+        assertTrue(countryTimeZones.matchesCountryCode("GB"));
+        assertTrue(countryTimeZones.matchesCountryCode("Gb"));
+        assertTrue(countryTimeZones.matchesCountryCode("gB"));
     }
 
     @Test
diff --git a/luni/src/test/native/ScopedIcuLocale.h b/luni/src/test/native/ScopedIcuLocale.h
new file mode 100644
index 0000000..851de76
--- /dev/null
+++ b/luni/src/test/native/ScopedIcuLocale.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SCOPED_ICU_LOCALE_H_included
+#define SCOPED_ICU_LOCALE_H_included
+
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include "unicode/locid.h"
+
+class ScopedIcuLocale {
+ public:
+  ScopedIcuLocale(JNIEnv* env, jstring javaLocaleName) : mEnv(env) {
+    mLocale.setToBogus();
+
+    if (javaLocaleName == NULL) {
+      jniThrowNullPointerException(mEnv, "javaLocaleName == null");
+      return;
+    }
+
+    const ScopedUtfChars localeName(env, javaLocaleName);
+    if (localeName.c_str() == NULL) {
+      return;
+    }
+
+    mLocale = icu::Locale::createFromName(localeName.c_str());
+  }
+
+  ~ScopedIcuLocale() {
+  }
+
+  bool valid() const {
+    return !mLocale.isBogus();
+  }
+
+  icu::Locale& locale() {
+    return mLocale;
+  }
+
+ private:
+  JNIEnv* const mEnv;
+  icu::Locale mLocale;
+
+  // Disallow copy and assignment.
+  ScopedIcuLocale(const ScopedIcuLocale&);
+  void operator=(const ScopedIcuLocale&);
+};
+
+#endif  // SCOPED_ICU_LOCALE_H_included
diff --git a/luni/src/test/native/libcore_libcore_icu_LocaleDataTest.cpp b/luni/src/test/native/libcore_libcore_icu_LocaleDataTest.cpp
new file mode 100644
index 0000000..477142b
--- /dev/null
+++ b/luni/src/test/native/libcore_libcore_icu_LocaleDataTest.cpp
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 1
+#define LOG_TAG "LocaleDataTest"
+
+#include <string.h>
+#include <memory>
+
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+#include "ScopedIcuLocale.h"
+#include "unicode/brkiter.h"
+#include "unicode/calendar.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/locid.h"
+#include "unicode/numfmt.h"
+#include "unicode/strenum.h"
+#include "unicode/ucasemap.h"
+#include "unicode/udat.h"
+#include "unicode/uloc.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+
+
+static jclass icu4cLocaleDataClass = nullptr;
+
+class ScopedResourceBundle {
+ public:
+  explicit ScopedResourceBundle(UResourceBundle* bundle) : bundle_(bundle) {
+  }
+
+  ~ScopedResourceBundle() {
+    if (bundle_ != NULL) {
+      ures_close(bundle_);
+    }
+  }
+
+  UResourceBundle* get() {
+    return bundle_;
+  }
+
+  bool hasKey(const char* key) {
+    UErrorCode status = U_ZERO_ERROR;
+    ures_getStringByKey(bundle_, key, NULL, &status);
+    return U_SUCCESS(status);
+  }
+
+ private:
+  UResourceBundle* bundle_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedResourceBundle);
+};
+
+template <typename T>
+static jobject valueOf(JNIEnv* env, jclass c, const char* signature, const T& value) {
+    static jmethodID valueOfMethod = env->GetStaticMethodID(c, "valueOf", signature);
+    if (env->ExceptionCheck()) {
+        return NULL;
+    }
+    jobject result = env->CallStaticObjectMethod(c, valueOfMethod, value);
+    if (env->ExceptionCheck()) {
+        return NULL;
+    }
+    return result;
+}
+
+static jobject integerValueOf(JNIEnv* env, jint value) {
+    return valueOf(env, env->FindClass("java/lang/Integer"), "(I)Ljava/lang/Integer;", value);
+}
+
+
+static bool setIntegerField(JNIEnv* env, jobject obj, const char* fieldName, int value) {
+  ScopedLocalRef<jobject> integerValue(env, integerValueOf(env, value));
+  if (integerValue.get() == NULL) return false;
+  jfieldID fid = env->GetFieldID(icu4cLocaleDataClass, fieldName, "Ljava/lang/Integer;");
+  env->SetObjectField(obj, fid, integerValue.get());
+  return true;
+}
+
+static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, jstring value) {
+    jfieldID fid = env->GetFieldID(icu4cLocaleDataClass, fieldName, "Ljava/lang/String;");
+    env->SetObjectField(obj, fid, value);
+    env->DeleteLocalRef(value);
+}
+
+static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, jobjectArray value) {
+    jfieldID fid = env->GetFieldID(icu4cLocaleDataClass, fieldName, "[Ljava/lang/String;");
+    env->SetObjectField(obj, fid, value);
+}
+
+static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString* valueArray, int32_t size) {
+  ScopedLocalRef<jobjectArray> result(env, env->NewObjectArray(size, env->FindClass("java/lang/String"), NULL));
+  for (int32_t i = 0; i < size ; i++) {
+    ScopedLocalRef<jstring> s(env, jniCreateString(env, valueArray[i].getBuffer(),valueArray[i].length()));
+    if (env->ExceptionCheck()) {
+      return;
+    }
+    env->SetObjectArrayElement(result.get(), i, s.get());
+    if (env->ExceptionCheck()) {
+      return;
+    }
+  }
+  setStringArrayField(env, obj, fieldName, result.get());
+}
+
+static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, UResourceBundle* bundle, int index) {
+  UErrorCode status = U_ZERO_ERROR;
+  int charCount;
+  const UChar* chars;
+  UResourceBundle* currentBundle = ures_getByIndex(bundle, index, NULL, &status);
+  switch (ures_getType(currentBundle)) {
+      case URES_STRING:
+         chars = ures_getString(currentBundle, &charCount, &status);
+         break;
+      case URES_ARRAY:
+         // In case there is an array, Android currently only cares about the
+         // first string of that array, the rest of the array is used by ICU
+         // for additional data ignored by Android.
+         chars = ures_getStringByIndex(currentBundle, 0, &charCount, &status);
+         break;
+      default:
+         status = U_INVALID_FORMAT_ERROR;
+  }
+  ures_close(currentBundle);
+
+  if (U_SUCCESS(status)) {
+    setStringField(env, obj, fieldName, jniCreateString(env, chars, charCount));
+  } else {
+    ALOGE("Error setting String field %s from ICU resource (index %d): %s", fieldName, index, u_errorName(status));
+  }
+}
+
+static void setCharField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString& value) {
+  if (value.length() == 0) {
+    return;
+  }
+  jfieldID fid = env->GetFieldID(icu4cLocaleDataClass, fieldName, "C");
+  env->SetCharField(obj, fid, value.charAt(0));
+}
+
+static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString& value) {
+  const UChar* chars = value.getBuffer();
+  setStringField(env, obj, fieldName, jniCreateString(env, chars, value.length()));
+}
+
+static void setNumberPatterns(JNIEnv* env, jobject obj, icu::Locale& locale) {
+  UErrorCode status = U_ZERO_ERROR;
+
+  icu::UnicodeString pattern;
+  std::unique_ptr<icu::DecimalFormat> fmt(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_CURRENCY, status)));
+  pattern = fmt->toPattern(pattern.remove());
+  setStringField(env, obj, "currencyPattern", pattern);
+
+  fmt.reset(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_DECIMAL, status)));
+  pattern = fmt->toPattern(pattern.remove());
+  setStringField(env, obj, "numberPattern", pattern);
+
+  fmt.reset(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_PERCENT, status)));
+  pattern = fmt->toPattern(pattern.remove());
+  setStringField(env, obj, "percentPattern", pattern);
+}
+
+static void setDecimalFormatSymbolsData(JNIEnv* env, jobject obj, icu::Locale& locale) {
+  UErrorCode status = U_ZERO_ERROR;
+  icu::DecimalFormatSymbols dfs(locale, status);
+
+  setCharField(env, obj, "decimalSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kDecimalSeparatorSymbol));
+  setCharField(env, obj, "groupingSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kGroupingSeparatorSymbol));
+  setCharField(env, obj, "patternSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kPatternSeparatorSymbol));
+  setStringField(env, obj, "percent", dfs.getSymbol(icu::DecimalFormatSymbols::kPercentSymbol));
+  setStringField(env, obj, "perMill", dfs.getSymbol(icu::DecimalFormatSymbols::kPerMillSymbol));
+  setCharField(env, obj, "monetarySeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kMonetarySeparatorSymbol));
+  setStringField(env, obj, "minusSign", dfs.getSymbol(icu::DecimalFormatSymbols:: kMinusSignSymbol));
+  setStringField(env, obj, "exponentSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kExponentialSymbol));
+  setStringField(env, obj, "infinity", dfs.getSymbol(icu::DecimalFormatSymbols::kInfinitySymbol));
+  setStringField(env, obj, "NaN", dfs.getSymbol(icu::DecimalFormatSymbols::kNaNSymbol));
+  setCharField(env, obj, "zeroDigit", dfs.getSymbol(icu::DecimalFormatSymbols::kZeroDigitSymbol));
+}
+
+
+// Iterates up through the locale hierarchy. So "en_US" would return "en_US", "en", "".
+class LocaleNameIterator {
+ public:
+  LocaleNameIterator(const char* locale_name, UErrorCode& status) : status_(status), has_next_(true) {
+    strcpy(locale_name_, locale_name);
+    locale_name_length_ = strlen(locale_name_);
+  }
+
+  const char* Get() {
+      return locale_name_;
+  }
+
+  bool HasNext() {
+    return has_next_;
+  }
+
+  void Up() {
+    if (locale_name_length_ == 0) {
+      has_next_ = false;
+    } else {
+      locale_name_length_ = uloc_getParent(locale_name_, locale_name_, sizeof(locale_name_), &status_);
+    }
+  }
+
+ private:
+  UErrorCode& status_;
+  bool has_next_;
+  char locale_name_[ULOC_FULLNAME_CAPACITY];
+  int32_t locale_name_length_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocaleNameIterator);
+};
+
+static bool getAmPmMarkersNarrow(JNIEnv* env, jobject localeData, const char* locale_name) {
+  UErrorCode status = U_ZERO_ERROR;
+  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle amPmMarkersNarrow(ures_getByKey(gregorian.get(), "AmPmMarkersNarrow", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  setStringField(env, localeData, "narrowAm", amPmMarkersNarrow.get(), 0);
+  setStringField(env, localeData, "narrowPm", amPmMarkersNarrow.get(), 1);
+  return true;
+}
+
+static bool getDateTimePatterns(JNIEnv* env, jobject localeData, const char* locale_name) {
+  UErrorCode status = U_ZERO_ERROR;
+  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle dateTimePatterns(ures_getByKey(gregorian.get(), "DateTimePatterns", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  setStringField(env, localeData, "fullTimeFormat", dateTimePatterns.get(), 0);
+  setStringField(env, localeData, "longTimeFormat", dateTimePatterns.get(), 1);
+  setStringField(env, localeData, "mediumTimeFormat", dateTimePatterns.get(), 2);
+  setStringField(env, localeData, "shortTimeFormat", dateTimePatterns.get(), 3);
+  setStringField(env, localeData, "fullDateFormat", dateTimePatterns.get(), 4);
+  setStringField(env, localeData, "longDateFormat", dateTimePatterns.get(), 5);
+  setStringField(env, localeData, "mediumDateFormat", dateTimePatterns.get(), 6);
+  setStringField(env, localeData, "shortDateFormat", dateTimePatterns.get(), 7);
+  return true;
+}
+
+extern "C" jboolean Java_libcore_libcore_icu_LocaleDataTest_initIcu4cLocaleData(JNIEnv* env,
+    jclass, jstring javaLanguageTag, jobject icu4cLocaleData, jobject dataClass) {
+  if (icu4cLocaleDataClass == nullptr) {
+    // It's okay to hold the class in the test.
+    icu4cLocaleDataClass = reinterpret_cast<jclass>(env->NewGlobalRef(dataClass));
+  }
+
+  // alias pointer
+  jobject localeData = icu4cLocaleData;
+
+  ScopedUtfChars languageTag(env, javaLanguageTag);
+  if (languageTag.c_str() == NULL) {
+    return JNI_FALSE;
+  }
+  if (languageTag.size() >= ULOC_FULLNAME_CAPACITY) {
+    return JNI_FALSE; // ICU has a fixed-length limit.
+  }
+
+  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  if (!icuLocale.valid()) {
+    return JNI_FALSE;
+  }
+
+  // Get the DateTimePatterns.
+  UErrorCode status = U_ZERO_ERROR;
+  bool foundDateTimePatterns = false;
+  for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
+    if (getDateTimePatterns(env, localeData, it.Get())) {
+      foundDateTimePatterns = true;
+      break;
+    }
+  }
+  if (!foundDateTimePatterns) {
+    ALOGE("Couldn't find ICU DateTimePatterns for %s", languageTag.c_str());
+    return JNI_FALSE;
+  }
+
+  // Get the narrow "AM" and "PM" strings.
+  bool foundAmPmMarkersNarrow = false;
+  for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
+    if (getAmPmMarkersNarrow(env, localeData, it.Get())) {
+      foundAmPmMarkersNarrow = true;
+      break;
+    }
+  }
+  if (!foundAmPmMarkersNarrow) {
+    ALOGE("Couldn't find ICU AmPmMarkersNarrow for %s", languageTag.c_str());
+    return JNI_FALSE;
+  }
+
+  status = U_ZERO_ERROR;
+  std::unique_ptr<icu::Calendar> cal(icu::Calendar::createInstance(icuLocale.locale(), status));
+  if (U_FAILURE(status)) {
+    return JNI_FALSE;
+  }
+  if (!setIntegerField(env, localeData, "firstDayOfWeek", cal->getFirstDayOfWeek())) {
+    return JNI_FALSE;
+  }
+  if (!setIntegerField(env, localeData, "minimalDaysInFirstWeek", cal->getMinimalDaysInFirstWeek())) {
+    return JNI_FALSE;
+  }
+
+  // Get DateFormatSymbols.
+  status = U_ZERO_ERROR;
+  icu::DateFormatSymbols dateFormatSym(icuLocale.locale(), status);
+  if (U_FAILURE(status)) {
+    return JNI_FALSE;
+  }
+
+  // Get AM/PM and BC/AD.
+  int32_t count = 0;
+  const icu::UnicodeString* amPmStrs = dateFormatSym.getAmPmStrings(count);
+  setStringArrayField(env, localeData, "amPm", amPmStrs, count);
+  const icu::UnicodeString* erasStrs = dateFormatSym.getEras(count);
+  setStringArrayField(env, localeData, "eras", erasStrs, count);
+
+  const icu::UnicodeString* longMonthNames =
+      dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::WIDE);
+  setStringArrayField(env, localeData, "longMonthNames", longMonthNames, count);
+  const icu::UnicodeString* shortMonthNames =
+      dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::ABBREVIATED);
+  setStringArrayField(env, localeData, "shortMonthNames", shortMonthNames, count);
+  const icu::UnicodeString* tinyMonthNames =
+      dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::NARROW);
+  setStringArrayField(env, localeData, "tinyMonthNames", tinyMonthNames, count);
+  const icu::UnicodeString* longWeekdayNames =
+      dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::WIDE);
+  setStringArrayField(env, localeData, "longWeekdayNames", longWeekdayNames, count);
+  const icu::UnicodeString* shortWeekdayNames =
+      dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::ABBREVIATED);
+  setStringArrayField(env, localeData, "shortWeekdayNames", shortWeekdayNames, count);
+  const icu::UnicodeString* tinyWeekdayNames =
+      dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::NARROW);
+  setStringArrayField(env, localeData, "tinyWeekdayNames", tinyWeekdayNames, count);
+
+  const icu::UnicodeString* longStandAloneMonthNames =
+      dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::WIDE);
+  setStringArrayField(env, localeData, "longStandAloneMonthNames", longStandAloneMonthNames, count);
+  const icu::UnicodeString* shortStandAloneMonthNames =
+      dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::ABBREVIATED);
+  setStringArrayField(env, localeData, "shortStandAloneMonthNames", shortStandAloneMonthNames, count);
+  const icu::UnicodeString* tinyStandAloneMonthNames =
+      dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::NARROW);
+  setStringArrayField(env, localeData, "tinyStandAloneMonthNames", tinyStandAloneMonthNames, count);
+  const icu::UnicodeString* longStandAloneWeekdayNames =
+      dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::WIDE);
+  setStringArrayField(env, localeData, "longStandAloneWeekdayNames", longStandAloneWeekdayNames, count);
+  const icu::UnicodeString* shortStandAloneWeekdayNames =
+      dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::ABBREVIATED);
+  setStringArrayField(env, localeData, "shortStandAloneWeekdayNames", shortStandAloneWeekdayNames, count);
+  const icu::UnicodeString* tinyStandAloneWeekdayNames =
+      dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::NARROW);
+  setStringArrayField(env, localeData, "tinyStandAloneWeekdayNames", tinyStandAloneWeekdayNames, count);
+
+  status = U_ZERO_ERROR;
+
+  // For numberPatterns and symbols.
+  setNumberPatterns(env, localeData, icuLocale.locale());
+  setDecimalFormatSymbolsData(env, localeData, icuLocale.locale());
+
+  return JNI_TRUE;
+}
diff --git a/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index 74d536f..c26dce3 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -988,8 +988,6 @@
     field public String[] tinyStandAloneMonthNames;
     field public String[] tinyStandAloneWeekdayNames;
     field public String[] tinyWeekdayNames;
-    field public String today;
-    field public String yesterday;
     field public char zeroDigit;
   }
 
@@ -1109,9 +1107,9 @@
     method public java.util.List<libcore.timezone.CountryTimeZones.TimeZoneMapping> getTimeZoneMappings();
     method public boolean hasUtcZone(long);
     method public boolean isDefaultTimeZoneBoosted();
-    method public boolean isForCountryCode(String);
     method public libcore.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(long, android.icu.util.TimeZone, int, boolean);
     method public libcore.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(long, android.icu.util.TimeZone, int);
+    method public boolean matchesCountryCode(String);
   }
 
   public static final class CountryTimeZones.OffsetResult {
diff --git a/ojluni/src/main/java/java/io/File.java b/ojluni/src/main/java/java/io/File.java
index 98956ca..0037534 100644
--- a/ojluni/src/main/java/java/io/File.java
+++ b/ojluni/src/main/java/java/io/File.java
@@ -518,7 +518,7 @@
 
     /* -- Path operations -- */
 
-    // Android-changed: Android-specific path information
+    // Android-changed: Android-specific path information.
     /**
      * Tests whether this abstract pathname is absolute.  The definition of
      * absolute pathname is system dependent.  On Android, absolute paths start with
@@ -531,7 +531,7 @@
         return fs.isAbsolute(this);
     }
 
-    // Android-changed: Android-specific path information
+    // Android-changed: Android-specific path information.
     /**
      * Returns the absolute path of this file. An absolute path is a path that starts at a root
      * of the file system. On Android, there is only one root: {@code /}.
@@ -737,8 +737,7 @@
 
     /* -- Attribute accessors -- */
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on android
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * Tests whether the application can read the file denoted by this
      * abstract pathname.
@@ -763,8 +762,7 @@
         return fs.checkAccess(this, FileSystem.ACCESS_READ);
     }
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on android
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * Tests whether the application can modify the file denoted by this
      * abstract pathname.
@@ -1450,8 +1448,7 @@
         return fs.setLastModifiedTime(this, time);
     }
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on Android.
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * Marks the file or directory named by this abstract pathname so that
      * only read operations are allowed. After invoking this method the file
@@ -1480,8 +1477,7 @@
         return fs.setReadOnly(this);
     }
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on Android.
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * Sets the owner's or everybody's write permission for this abstract
      * pathname.
@@ -1523,8 +1519,7 @@
         return fs.setPermission(this, FileSystem.ACCESS_WRITE, writable, ownerOnly);
     }
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on Android.
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * A convenience method to set the owner's write permission for this abstract
      * pathname.
@@ -1554,8 +1549,7 @@
         return setWritable(writable, true);
     }
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on Android.
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * Sets the owner's or everybody's read permission for this abstract
      * pathname.
@@ -1600,8 +1594,7 @@
         return fs.setPermission(this, FileSystem.ACCESS_READ, readable, ownerOnly);
     }
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on Android.
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * A convenience method to set the owner's read permission for this abstract
      * pathname.
@@ -1634,8 +1627,7 @@
         return setReadable(readable, true);
     }
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on Android.
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * Sets the owner's or everybody's execute permission for this abstract
      * pathname.
@@ -1680,8 +1672,7 @@
         return fs.setPermission(this, FileSystem.ACCESS_EXECUTE, executable, ownerOnly);
     }
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on Android.
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * A convenience method to set the owner's execute permission for this
      * abstract pathname.
@@ -1714,8 +1705,7 @@
         return setExecutable(executable, true);
     }
 
-    // Android-changed. Removed javadoc comment about special privileges
-    // that doesn't make sense on Android.
+    // Android-changed: Removed inapplicable javadoc comment about special privileges.
     /**
      * Tests whether the application can execute the file denoted by this
      * abstract pathname.
@@ -1873,8 +1863,7 @@
     private static class TempDirectory {
         private TempDirectory() { }
 
-        // Android-changed: Don't cache java.io.tmpdir value
-        // temporary directory location.
+        // Android-changed: Don't cache java.io.tmpdir value temporary directory location.
         /*
         private static final File tmpdir = new File(AccessController
            .doPrivileged(new GetPropertyAction("java.io.tmpdir")));
@@ -1888,8 +1877,8 @@
         static File generateFile(String prefix, String suffix, File dir)
             throws IOException
         {
-            // Android-changed: Use Math.randomIntInternal. This (pseudo) random number
-            // is initialized post-fork
+            // Android-changed: Use Math.randomIntInternal.
+            // This (pseudo) random number is initialized post-fork.
 
             long n = Math.randomLongInternal();
             if (n == Long.MIN_VALUE) {
@@ -1898,7 +1887,7 @@
                 n = Math.abs(n);
             }
 
-            // Android-changed: Reject invalid file prefixes
+            // Android-changed: Reject invalid file prefixes.
             // Use only the file name from the supplied prefix
             // prefix = (new File(prefix)).getName();
 
diff --git a/ojluni/src/main/java/java/io/FileDescriptor.java b/ojluni/src/main/java/java/io/FileDescriptor.java
index ed3ebfe..8584020 100644
--- a/ojluni/src/main/java/java/io/FileDescriptor.java
+++ b/ojluni/src/main/java/java/io/FileDescriptor.java
@@ -47,11 +47,11 @@
  * @since   JDK1.0
  */
 public final class FileDescriptor {
-    // Android-changed: Removed parent reference counting. Creator is responsible for closing
-    // the file descriptor.
+    // Android-changed: Removed parent reference counting.
+    // The creator is responsible for closing the file descriptor.
 
-    // Android-changed: Renamed fd to descriptor to avoid issues with JNI/reflection
-    // fetching the descriptor value.
+    // Android-changed: Renamed fd to descriptor.
+    // Renaming is to avoid issues with JNI/reflection fetching the descriptor value.
     private int descriptor;
 
     // Android-added: Track fd owner to guard against accidental closure. http://b/110100358
@@ -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.
@@ -145,11 +142,11 @@
      */
     public native void sync() throws SyncFailedException;
 
-    // Android-removed: initIDs not used to allow compile-time intialization
+    // Android-removed: initIDs not used to allow compile-time initialization.
     /* This routine initializes JNI field offsets for the class */
     //private static native void initIDs();
 
-    // Android-added: Needed for framework to access descriptor value
+    // Android-added: Needed for framework to access descriptor value.
     /**
      * Returns the int descriptor. It's highly unlikely you should be calling this. Please discuss
      * your needs with a libcore maintainer before using this method.
@@ -159,7 +156,7 @@
         return descriptor;
     }
 
-    // Android-added: Needed for framework to access descriptor value
+    // Android-added: Needed for framework to access descriptor value.
     /**
      * Sets the int descriptor. It's highly unlikely you should be calling this. Please discuss
      * your needs with a libcore maintainer before using this method.
@@ -169,6 +166,26 @@
         this.descriptor = fd;
     }
 
+    // BEGIN Android-added: Method to clone standard file descriptors.
+    // Required as a consequence of RuntimeInit#redirectLogStreams. Cloning is used in
+    // ZygoteHooks.onEndPreload().
+    /**
+     * Clones the current native file descriptor and uses this for this FileDescriptor instance.
+     *
+     * This method does not close the current native file descriptor.
+     *
+     * @hide internal use only
+     */
+    public void cloneForFork() {
+        try {
+            int newDescriptor = Os.fcntlInt(this, F_DUPFD_CLOEXEC, 0);
+            this.descriptor = newDescriptor;
+        } catch (ErrnoException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    // END Android-added: Method to clone standard file descriptors.
+
     // BEGIN Android-added: Methods to enable ownership enforcement of Unix file descriptors.
     /**
      * Returns the owner ID of this FileDescriptor. It's highly unlikely you should be calling this.
@@ -206,7 +223,7 @@
     }
     // END Android-added: Methods to enable ownership enforcement of Unix file descriptors.
 
-    // Android-added: Needed for framework to test if it's a socket
+    // Android-added: Needed for framework to test if it's a socket.
     /**
      * @hide internal use only
      */
@@ -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 {
@@ -246,5 +254,5 @@
             }
         );
     }
-// Android-removed: Removed method required for parents reference counting
+// Android-removed: Removed method required for parents reference counting.
 }
diff --git a/ojluni/src/main/java/java/io/ObjectOutputStream.java b/ojluni/src/main/java/java/io/ObjectOutputStream.java
index ccec944..1f7f901 100644
--- a/ojluni/src/main/java/java/io/ObjectOutputStream.java
+++ b/ojluni/src/main/java/java/io/ObjectOutputStream.java
@@ -1223,7 +1223,7 @@
                 writeClass((Class) obj, unshared);
             } else if (obj instanceof ObjectStreamClass) {
                 writeClassDesc((ObjectStreamClass) obj, unshared);
-            // END Android-changed:  Make Class and ObjectStreamClass replaceable.
+            // END Android-changed: Make Class and ObjectStreamClass replaceable.
             } else if (obj instanceof String) {
                 writeString((String) obj, unshared);
             } else if (cl.isArray()) {
@@ -1865,7 +1865,7 @@
             return blkmode;
         }
 
-        // BEGIN Android-added: Warning about writing to closed ObjectOutputStream
+        // BEGIN Android-added: Warning about writing to closed ObjectOutputStream.
         /**
          * Warns if the stream has been closed.
          *
@@ -1884,7 +1884,7 @@
                 warnOnceWhenWriting = false;
             }
         }
-        // END Android-added: Warning about writing to closed ObjectOutputStream
+        // END Android-added: Warning about writing to closed ObjectOutputStream.
 
         /* ----------------- generic output stream methods ----------------- */
         /*
@@ -1916,7 +1916,7 @@
         public void close() throws IOException {
             flush();
             out.close();
-            // Android-added: Warning about writing to closed ObjectOutputStream
+            // Android-added: Warning about writing to closed ObjectOutputStream.
             warnOnceWhenWriting = true;
         }
 
@@ -1932,7 +1932,7 @@
             if (!(copy || blkmode)) {           // write directly
                 drain();
                 out.write(b, off, len);
-                // Android-added: Warning about writing to closed ObjectOutputStream
+                // Android-added: Warning about writing to closed ObjectOutputStream.
                 warnIfClosed();
                 return;
             }
@@ -1955,7 +1955,7 @@
                     len -= wlen;
                 }
             }
-            // Android-added: Warning about writing to closed ObjectOutputStream
+            // Android-added: Warning about writing to closed ObjectOutputStream.
             warnIfClosed();
         }
 
@@ -1972,7 +1972,7 @@
             }
             out.write(buf, 0, pos);
             pos = 0;
-            // Android-added: Warning about writing to closed ObjectOutputStream
+            // Android-added: Warning about writing to closed ObjectOutputStream.
             warnIfClosed();
         }
 
@@ -1991,7 +1991,7 @@
                 Bits.putInt(hbuf, 1, len);
                 out.write(hbuf, 0, 5);
             }
-            // Android-added: Warning about writing to closed ObjectOutputStream
+            // Android-added: Warning about writing to closed ObjectOutputStream.
             warnIfClosed();
         }
 
diff --git a/ojluni/src/main/java/java/io/ObjectStreamClass.java b/ojluni/src/main/java/java/io/ObjectStreamClass.java
index a88ad63..9a1a48f 100644
--- a/ojluni/src/main/java/java/io/ObjectStreamClass.java
+++ b/ojluni/src/main/java/java/io/ObjectStreamClass.java
@@ -1425,12 +1425,12 @@
             {
                 return null;
             }
-            // BEGIN Android-changed: Serialization constructor obtained differently
+            // BEGIN Android-changed: Serialization constructor obtained differently.
             // cons = reflFactory.newConstructorForSerialization(cl, cons);
             if (cons.getDeclaringClass() != cl) {
                 cons = cons.serializationCopy(cons.getDeclaringClass(), cl);
             }
-            // END Android-changed: Serialization constructor obtained differently
+            // END Android-changed: Serialization constructor obtained differently.
             cons.setAccessible(true);
             return cons;
         } catch (NoSuchMethodException ex) {
@@ -1797,7 +1797,7 @@
                 }
             }
 
-            // BEGIN Android-changed: Fix/log clinit serialization workaround b/29064453
+            // BEGIN Android-changed: Fix/log clinit serialization workaround. b/29064453
             // Prior to SDK 24 hasStaticInitializer() would return true if the superclass had a
             // static initializer, that was contrary to the specification. In SDK 24 the default
             // behavior was corrected but the old behavior was preserved for apps that targeted 23
@@ -1817,7 +1817,7 @@
                     // instructions to the developer on how to fix the problems.
                     warnIncompatibleSUIDChange = true;
                 }
-                // END Android-changed: Fix/log clinit serialization workaround b/29064453
+            // END Android-changed: Fix/log clinit serialization workaround. b/29064453
                 dout.writeUTF("<clinit>");
                 dout.writeInt(Modifier.STATIC);
                 dout.writeUTF("()V");
@@ -1882,14 +1882,14 @@
             for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
                 hash = (hash << 8) | (hashBytes[i] & 0xFF);
             }
-            // BEGIN Android-added: Fix/log clinit serialization workaround b/29064453
+            // BEGIN Android-added: Fix/log clinit serialization workaround. b/29064453
             // ObjectStreamClass instances are cached per Class and caches its default
             // serialVersionUID so it will only log one message per class per app process
             // irrespective of the number of times the class is serialized.
             if (warnIncompatibleSUIDChange) {
                 suidCompatibilityListener.warnDefaultSUIDTargetVersionDependent(cl, hash);
             }
-            // END Android-added: Fix/log clinit serialization workaround b/29064453
+            // END Android-added: Fix/log clinit serialization workaround. b/29064453
             return hash;
         } catch (IOException ex) {
             throw new InternalError(ex);
@@ -1898,7 +1898,7 @@
         }
     }
 
-    // BEGIN Android-changed: Fix/log clinit serialization workaround b/29064453
+    // BEGIN Android-changed: Fix/log clinit serialization workaround. b/29064453
     /**
      * Created for testing as there is no nice way to detect when a message is logged.
      *
@@ -1943,7 +1943,7 @@
      */
     private native static boolean hasStaticInitializer(
         Class<?> cl, boolean inheritStaticInitializer);
-    // END Android-changed: Fix/log clinit serialization workaround b/29064453
+    // END Android-changed: Fix/log clinit serialization workaround. b/29064453
 
     /**
      * Class for computing and caching field/constructor/method signatures
diff --git a/ojluni/src/main/java/java/lang/Class.java b/ojluni/src/main/java/java/lang/Class.java
index f792248..478c339 100644
--- a/ojluni/src/main/java/java/lang/Class.java
+++ b/ojluni/src/main/java/java/lang/Class.java
@@ -1135,7 +1135,7 @@
      *     that class is a local or anonymous class; otherwise {@code null}.
      * @since 1.5
      */
-    // Android-changed: Removed SecurityException
+    // Android-changed: Removed SecurityException.
     public Method getEnclosingMethod() {
         if (classNameImpliesTopLevel()) {
             return null;
@@ -1157,7 +1157,7 @@
      *     that class is a local or anonymous class; otherwise {@code null}.
      * @since 1.5
      */
-    // Android-changed: Removed SecurityException
+    // Android-changed: Removed SecurityException.
     public Constructor<?> getEnclosingConstructor() {
         if (classNameImpliesTopLevel()) {
             return null;
@@ -1184,7 +1184,7 @@
      * @return the declaring class for this class
      * @since JDK1.1
      */
-    // Android-changed: Removed SecurityException
+    // Android-changed: Removed SecurityException.
     @FastNative
     public native Class<?> getDeclaringClass();
 
@@ -1195,7 +1195,7 @@
      * @return the immediately enclosing class of the underlying class
      * @since 1.5
      */
-    // Android-changed: Removed SecurityException
+    // Android-changed: Removed SecurityException.
     @FastNative
     public native Class<?> getEnclosingClass();
 
@@ -1593,7 +1593,7 @@
      * @jls 8.2 Class Members
      * @jls 8.3 Field Declarations
      */
-    // Android-changed: Removed SecurityException
+    // Android-changed: Removed SecurityException.
     public Field getField(String name)
         throws NoSuchFieldException {
         if (name == null) {
@@ -1764,7 +1764,7 @@
      *
      * @since JDK1.1
      */
-    // Android-changed: Removed SecurityException
+    // Android-changed: Removed SecurityException.
     @FastNative
     public native Class<?>[] getDeclaredClasses();
 
@@ -1810,7 +1810,7 @@
      * @jls 8.2 Class Members
      * @jls 8.3 Field Declarations
      */
-    // Android-changed: Removed SecurityException
+    // Android-changed: Removed SecurityException.
     @FastNative
     public native Field[] getDeclaredFields();
 
@@ -1986,7 +1986,7 @@
      * @jls 8.2 Class Members
      * @jls 8.3 Field Declarations
      */
-    // Android-changed: Removed SecurityException
+    // Android-changed: Removed SecurityException.
     @FastNative
     public native Field getDeclaredField(String name) throws NoSuchFieldException;
 
diff --git a/ojluni/src/main/java/java/lang/System.java b/ojluni/src/main/java/java/lang/System.java
index 9cec068..a67bb0b 100644
--- a/ojluni/src/main/java/java/lang/System.java
+++ b/ojluni/src/main/java/java/lang/System.java
@@ -983,12 +983,13 @@
 
         p.put("java.vm.version", runtime.vmVersion());
 
+        String userName;
         try {
-            StructPasswd passwd = Libcore.os.getpwuid(Libcore.os.getuid());
-            p.put("user.name", passwd.pw_name);
+            userName = Libcore.os.getpwuid(Libcore.os.getuid()).pw_name;
         } catch (ErrnoException exception) {
-            throw new AssertionError(exception);
+            userName = "unknown";
         }
+        p.put("user.name", userName);
 
         StructUtsname info = Libcore.os.uname();
         p.put("os.arch", info.machine);
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index d06db86..0ff38a6 100644
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -485,10 +485,10 @@
         this.name = name;
 
         Thread parent = currentThread();
-        // Android-removed: SecurityManager stubbed out on Android
+        // Android-removed: SecurityManager stubbed out on Android.
         // SecurityManager security = System.getSecurityManager();
         if (g == null) {
-            // Android-changed: SecurityManager stubbed out on Android
+            // Android-changed: SecurityManager stubbed out on Android.
             /*
             /* Determine if it's an applet or not *
 
@@ -506,7 +506,7 @@
             // }
         }
 
-        // Android-removed: SecurityManager stubbed out on Android
+        // Android-removed: SecurityManager stubbed out on Android.
         /*
         /* checkAccess regardless of whether or not threadgroup is
            explicitly passed in. *
@@ -1579,7 +1579,7 @@
      * @see        SecurityManager#checkAccess(Thread)
      */
     public final void checkAccess() {
-        // Android-removed: SecurityManager stubbed out on Android
+        // Android-removed: SecurityManager stubbed out on Android.
         // SecurityManager security = System.getSecurityManager();
         // if (security != null) {
         //     security.checkAccess(this);
@@ -1631,7 +1631,7 @@
      */
     @CallerSensitive
     public ClassLoader getContextClassLoader() {
-        // Android-removed: SecurityManager stubbed out on Android
+        // Android-removed: SecurityManager stubbed out on Android.
         /*
         if (contextClassLoader == null)
             return null;
@@ -1667,7 +1667,7 @@
      * @since 1.2
      */
     public void setContextClassLoader(ClassLoader cl) {
-        // Android-removed: SecurityManager stubbed out on Android
+        // Android-removed: SecurityManager stubbed out on Android.
         // SecurityManager sm = System.getSecurityManager();
         // if (sm != null) {
         //     sm.checkPermission(new RuntimePermission("setContextClassLoader"));
@@ -1774,7 +1774,7 @@
      * @since 1.5
      */
     public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
-        // Android-removed: SecurityManager stubbed out on Android
+        // Android-removed: SecurityManager stubbed out on Android.
         /*
         // check for getStackTrace permission
         SecurityManager security = System.getSecurityManager();
@@ -2098,7 +2098,7 @@
      * @since 1.5
      */
     public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
-        // Android-removed: SecurityManager stubbed out on Android
+        // Android-removed: SecurityManager stubbed out on Android.
         /*
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
diff --git a/ojluni/src/main/java/java/lang/Throwable.java b/ojluni/src/main/java/java/lang/Throwable.java
index 5a3f8a8..7596681 100644
--- a/ojluni/src/main/java/java/lang/Throwable.java
+++ b/ojluni/src/main/java/java/lang/Throwable.java
@@ -155,7 +155,7 @@
             new StackTraceElement[] {STACK_TRACE_ELEMENT_SENTINEL};
     }
 
-    // Android-removed: Use libcore.util.EmptyArray for the empty stack trace
+    // Android-removed: Use libcore.util.EmptyArray for the empty stack trace.
     // Adding the constant UNASSIGNED_STACK breaks serialization of some subclasses
     // /**
     //  * A shared value for an empty stack.
@@ -211,11 +211,11 @@
      * @serial
      * @since 1.4
      */
-    // Android-changed: Use libcore.util.EmptyArray for the empty stack trace
+    // Android-changed: Use libcore.util.EmptyArray for the empty stack trace.
     // private StackTraceElement[] stackTrace = UNASSIGNED_STACK;
     private StackTraceElement[] stackTrace = libcore.util.EmptyArray.STACK_TRACE_ELEMENT;
 
-    // Android-removed: Use empty collection in place of SUPPRESSED_SENTINEL
+    // Android-removed: Use empty collection in place of SUPPRESSED_SENTINEL.
     // Adding this constant breaks serialization of some subclasses
     /*
     // Setting this static field introduces an acceptable
@@ -234,7 +234,7 @@
      * @serial
      * @since 1.7
      */
-    // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL
+    // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL.
     // private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL;
     private List<Throwable> suppressedExceptions = Collections.emptyList();
 
@@ -689,7 +689,7 @@
                                          String caption,
                                          String prefix,
                                          Set<Throwable> dejaVu) {
-        // Android-removed: Use of assert keyword which breaks serialization of some subclasses
+        // Android-removed: Use of assert keyword which breaks serialization of some subclasses.
         // (Using assert adds a static field that determines whether assertions are enabled.)
         // assert Thread.holdsLock(s.lock());
         if (dejaVu.contains(this)) {
@@ -794,17 +794,17 @@
     public synchronized Throwable fillInStackTrace() {
         if (stackTrace != null ||
             backtrace != null /* Out of protocol state */ ) {
-            // Android-changed: Use Android-specific nativeFillInStackTrace
+            // Android-changed: Use Android-specific nativeFillInStackTrace.
             // fillInStackTrace(0);
             backtrace = nativeFillInStackTrace();
-            // Android-changed: Use libcore.util.EmptyArray for the empty stack trace
+            // Android-changed: Use libcore.util.EmptyArray for the empty stack trace.
             // stackTrace = UNASSIGNED_STACK;
             stackTrace = libcore.util.EmptyArray.STACK_TRACE_ELEMENT;
         }
         return this;
     }
 
-    // Android-changed: Use Android-specific nativeFillInStackTrace
+    // Android-changed: Use Android-specific nativeFillInStackTrace.
     // private native Throwable fillInStackTrace(int dummy);
     @FastNative
     private static native Object nativeFillInStackTrace();
@@ -840,11 +840,11 @@
     private synchronized StackTraceElement[] getOurStackTrace() {
         // Initialize stack trace field with information from
         // backtrace if this is the first call to this method
-        // Android-changed: Use libcore.util.EmptyArray for the empty stack trace
+        // Android-changed: Use libcore.util.EmptyArray for the empty stack trace.
         // if (stackTrace == UNASSIGNED_STACK ||
         if (stackTrace == libcore.util.EmptyArray.STACK_TRACE_ELEMENT ||
             (stackTrace == null && backtrace != null) /* Out of protocol state */) {
-            // BEGIN Android-changed: Use Android-specific nativeGetStackTrace
+            // BEGIN Android-changed: Use Android-specific nativeGetStackTrace.
             // int depth = getStackTraceDepth();
             // stackTrace = new StackTraceElement[depth];
             // for (int i=0; i < depth; i++)
@@ -854,9 +854,9 @@
             if (stackTrace == null) {
                 return libcore.util.EmptyArray.STACK_TRACE_ELEMENT;
             }
-            // END Android-changed: Use Android-specific nativeGetStackTrace
+            // END Android-changed: Use Android-specific nativeGetStackTrace.
         } else if (stackTrace == null) {
-            // Android-changed: Use libcore.util.EmptyArray for the empty stack trace
+            // Android-changed: Use libcore.util.EmptyArray for the empty stack trace.
             // return UNASSIGNED_STACK;
             return libcore.util.EmptyArray.STACK_TRACE_ELEMENT;
         }
@@ -907,7 +907,7 @@
         }
     }
 
-    // Android-removed: Unused native method getStackTraceDepth()
+    // Android-removed: Unused native method getStackTraceDepth().
     // /**
     //  * Returns the number of elements in the stack trace (or 0 if the stack
     //  * trace is unavailable).
@@ -925,7 +925,7 @@
      * @throws IndexOutOfBoundsException if {@code index < 0 ||
      *         index >= getStackTraceDepth() }
      */
-    // Android-changed: Use Android-specific nativeGetStackTrace
+    // Android-changed: Use Android-specific nativeGetStackTrace.
     // native StackTraceElement getStackTraceElement(int index);
     @FastNative
     private static native StackTraceElement[] nativeGetStackTrace(Object stackState);
@@ -953,7 +953,7 @@
             List<Throwable> suppressed = null;
             if (suppressedExceptions.isEmpty()) {
                 // Use the sentinel for a zero-length list
-                // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL
+                // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL.
                 // suppressed = SUPPRESSED_SENTINEL;
                 suppressed = Collections.emptyList();
             } else { // Copy Throwables to new list
@@ -982,7 +982,7 @@
          */
         if (stackTrace != null) {
             if (stackTrace.length == 0) {
-                // Android-removed: clone() call not needed because of libcore.util.EmptyArray usage
+                // Android-removed: clone() call unneeded because of libcore.util.EmptyArray usage.
                 // stackTrace = UNASSIGNED_STACK.clone();
             }  else if (stackTrace.length == 1 &&
                         // Check for the marker of an immutable stack trace
@@ -999,7 +999,7 @@
             // from an exception serialized without that field in
             // older JDK releases; treat such exceptions as having
             // empty stack traces.
-            // Android-changed: Directly create empty array instead of cloning UNASSIGNED_STACK
+            // Android-changed: Directly create empty array instead of cloning UNASSIGNED_STACK.
             // stackTrace = UNASSIGNED_STACK.clone();
             stackTrace = new StackTraceElement[0];
         }
@@ -1090,7 +1090,7 @@
         if (suppressedExceptions == null) // Suppressed exceptions not recorded
             return;
 
-        // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL
+        // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL.
         // if (suppressedExceptions == SUPPRESSED_SENTINEL)
         if (suppressedExceptions.isEmpty())
             suppressedExceptions = new ArrayList<>(1);
@@ -1098,7 +1098,7 @@
         suppressedExceptions.add(exception);
     }
 
-    // Android-changed: Lazily initialize EMPTY_THROWABLE_ARRAY
+    // Android-changed: Lazily initialize EMPTY_THROWABLE_ARRAY.
     // private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
     private static Throwable[] EMPTY_THROWABLE_ARRAY;
 
@@ -1118,12 +1118,12 @@
      * @since 1.7
      */
     public final synchronized Throwable[] getSuppressed() {
-        // Android-added: Lazily initialize EMPTY_THROWABLE_ARRAY
+        // Android-added: Lazily initialize EMPTY_THROWABLE_ARRAY.
         if (EMPTY_THROWABLE_ARRAY == null) {
             EMPTY_THROWABLE_ARRAY = new Throwable[0];
         }
 
-        // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL
+        // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL.
         // if (suppressedExceptions == SUPPRESSED_SENTINEL ||
         //    suppressedExceptions == null)
         if (suppressedExceptions == null || suppressedExceptions.isEmpty())
diff --git a/ojluni/src/main/java/java/lang/invoke/CallSite.java b/ojluni/src/main/java/java/lang/invoke/CallSite.java
index 85b4bb9..069b2fd 100644
--- a/ojluni/src/main/java/java/lang/invoke/CallSite.java
+++ b/ojluni/src/main/java/java/lang/invoke/CallSite.java
@@ -25,7 +25,7 @@
 
 package java.lang.invoke;
 
-// Android-changed: Not using Empty
+// Android-changed: Not using Empty.
 //import sun.invoke.empty.Empty;
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@@ -104,9 +104,10 @@
      */
     /*package-private*/
     CallSite(MethodType type) {
-        // Android-changed: No cache for these so create uninitializedCallSite target here using
-        // method handle transformations to create a method handle that has the expected method
-        // type but throws an IllegalStateException.
+        // Android-changed: No cache for these.
+        // Instead create uninitializedCallSite target here using method handle transformations
+        // to create a method handle that has the expected method type but throws an
+        // IllegalStateException.
         // target = makeUninitializedCallSite(type);
         this.target = MethodHandles.throwException(type.returnType(), IllegalStateException.class);
         this.target = MethodHandles.insertArguments(
@@ -115,8 +116,7 @@
             this.target = MethodHandles.dropArguments(this.target, 0, type.ptypes());
         }
 
-        // Android-changed: Using initializer method for GET_TARGET
-        // rather than complex static initializer.
+        // Android-changed: Using initializer method for GET_TARGET instead of static initializer.
         initializeGetTarget();
     }
 
@@ -130,8 +130,7 @@
         target.type();  // null check
         this.target = target;
 
-        // Android-changed: Using initializer method for GET_TARGET
-        // rather than complex static initializer.
+        // Android-changed: Using initializer method for GET_TARGET instead of static initializer.
         initializeGetTarget();
     }
 
@@ -153,8 +152,7 @@
         checkTargetChange(this.target, boundTarget);
         this.target = boundTarget;
 
-        // Android-changed: Using initializer method for GET_TARGET
-        // rather than complex static initializer.
+        // Android-changed: Using initializer method for GET_TARGET instead of static initializer.
         initializeGetTarget();
     }
 
@@ -244,9 +242,9 @@
     private static MethodHandle GET_TARGET = null;
 
     private void initializeGetTarget() {
-        // Android-changed: moved from static initializer for
-        // GET_TARGET to avoid issues with running early. Called from
-        // constructors. CallSite creation is not performance critical.
+        // Android-changed: moved from static initializer for GET_TARGET.
+        // This avoids issues with running early. Called from constructors.
+        // CallSite creation is not performance critical.
         synchronized (CallSite.class) {
             if (GET_TARGET == null) {
                 try {
diff --git a/ojluni/src/main/java/java/lang/reflect/Array.java b/ojluni/src/main/java/java/lang/reflect/Array.java
index 95a8091..db7e9a2 100644
--- a/ojluni/src/main/java/java/lang/reflect/Array.java
+++ b/ojluni/src/main/java/java/lang/reflect/Array.java
@@ -111,7 +111,7 @@
      */
     public static Object newInstance(Class<?> componentType, int... dimensions)
         throws IllegalArgumentException, NegativeArraySizeException {
-        // Android-changed: New implementation of newInstance(Class, int...)
+        // Android-changed: New implementation of newInstance(Class, int...).
         if (dimensions.length <= 0 || dimensions.length > 255) {
             throw new IllegalArgumentException("Bad number of dimensions: " + dimensions.length);
         }
@@ -132,7 +132,7 @@
      * @exception IllegalArgumentException if the object argument is not
      * an array
      */
-    // Android-changed: Non-native implementation of getLength(Object)
+    // Android-changed: Non-native implementation of getLength(Object).
     // Android-changed: Removal of explicit throws IllegalArgumentException from method signature.
     public static int getLength(Object array)
         /* throws IllegalArgumentException */ {
@@ -174,7 +174,7 @@
      * argument is negative, or if it is greater than or equal to the
      * length of the specified array
      */
-    // Android-changed: Non-native implementation of get(Object, int)
+    // Android-changed: Non-native implementation of get(Object, int).
     public static Object get(Object array, int index)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof Object[]) {
@@ -226,7 +226,7 @@
      * length of the specified array
      * @see Array#get
      */
-    // Android-changed: Non-native implementation of getBoolean(Object, int)
+    // Android-changed: Non-native implementation of getBoolean(Object, int).
     public static boolean getBoolean(Object array, int index)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof boolean[]) {
@@ -251,7 +251,7 @@
      * length of the specified array
      * @see Array#get
      */
-    // Android-changed: Non-native implementation of getByte(Object, int)
+    // Android-changed: Non-native implementation of getByte(Object, int).
     public static byte getByte(Object array, int index)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof byte[]) {
@@ -276,7 +276,7 @@
      * length of the specified array
      * @see Array#get
      */
-    // Android-changed: Non-native implementation of getChar(Object, int)
+    // Android-changed: Non-native implementation of getChar(Object, int).
     public static char getChar(Object array, int index)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof char[]) {
@@ -301,7 +301,7 @@
      * length of the specified array
      * @see Array#get
      */
-    // Android-changed: Non-native implementation of getShort(Object, int)
+    // Android-changed: Non-native implementation of getShort(Object, int).
     public static short getShort(Object array, int index)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof short[]) {
@@ -328,7 +328,7 @@
      * length of the specified array
      * @see Array#get
      */
-    // Android-changed: Non-native implementation of getInt(Object, int)
+    // Android-changed: Non-native implementation of getInt(Object, int).
     public static int getInt(Object array, int index)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof int[]) {
@@ -359,7 +359,7 @@
      * length of the specified array
      * @see Array#get
      */
-    // Android-changed: Non-native implementation of getLong(Object, int)
+    // Android-changed: Non-native implementation of getLong(Object, int).
     public static long getLong(Object array, int index)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof long[]) {
@@ -392,7 +392,7 @@
      * length of the specified array
      * @see Array#get
      */
-    // Android-changed: Non-native implementation of getFloat(Object, int)
+    // Android-changed: Non-native implementation of getFloat(Object, int).
     public static float getFloat(Object array, int index)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof float[]) {
@@ -427,7 +427,7 @@
      * length of the specified array
      * @see Array#get
      */
-    // Android-changed: Non-native implementation of getDouble(Object, int)
+    // Android-changed: Non-native implementation of getDouble(Object, int).
     public static double getDouble(Object array, int index)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof double[]) {
@@ -465,7 +465,7 @@
      * argument is negative, or if it is greater than or equal to
      * the length of the specified array
      */
-    // Android-changed: Non-native implementation of set(Object, int, Object)
+    // Android-changed: Non-native implementation of set(Object, int, Object).
     public static void set(Object array, int index, Object value)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (!array.getClass().isArray()) {
@@ -518,8 +518,8 @@
      * the length of the specified array
      * @see Array#set
      */
-    // Android-changed: Non-native implementation of setBoolean(Object, int, boolean)
-    // Android-changed: Removal of explicit runtime exceptions throws clause
+    // Android-changed: Non-native implementation of setBoolean(Object, int, boolean).
+    // Android-changed: Removal of explicit runtime exceptions throws clause.
     public static void setBoolean(Object array, int index, boolean z)
         /* throws IllegalArgumentException, ArrayIndexOutOfBoundsException */ {
         if (array instanceof boolean[]) {
@@ -546,7 +546,7 @@
      * the length of the specified array
      * @see Array#set
      */
-    // Android-changed: Non-native implementation of setByte(Object, int, byte)
+    // Android-changed: Non-native implementation of setByte(Object, int, byte).
     public static void setByte(Object array, int index, byte b)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof byte[]) {
@@ -583,7 +583,7 @@
      * the length of the specified array
      * @see Array#set
      */
-    // Android-changed: Non-native implementation of setChar(Object, int, char)
+    // Android-changed: Non-native implementation of setChar(Object, int, char).
     public static void setChar(Object array, int index, char c)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof char[]) {
@@ -618,7 +618,7 @@
      * the length of the specified array
      * @see Array#set
      */
-    // Android-changed: Non-native implementation of setShort(Object, int, short)
+    // Android-changed: Non-native implementation of setShort(Object, int, short).
     public static void setShort(Object array, int index, short s)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof short[]) {
@@ -653,7 +653,7 @@
      * the length of the specified array
      * @see Array#set
      */
-    // Android-changed: Non-native implementation of setInt(Object, int, int)
+    // Android-changed: Non-native implementation of setInt(Object, int, int).
     public static void setInt(Object array, int index, int i)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof int[]) {
@@ -686,7 +686,7 @@
      * the length of the specified array
      * @see Array#set
      */
-    // Android-changed: Non-native implementation of setBoolean(Object, int, long)
+    // Android-changed: Non-native implementation of setBoolean(Object, int, long).
     public static void setLong(Object array, int index, long l)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof long[]) {
@@ -745,7 +745,7 @@
      * the length of the specified array
      * @see Array#set
      */
-    // Android-changed: Non-native implementation of setDouble(Object, int, double)
+    // Android-changed: Non-native implementation of setDouble(Object, int, double).
     public static void setDouble(Object array, int index, double d)
         throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
         if (array instanceof double[]) {
@@ -759,7 +759,7 @@
      * Private
      */
 
-    // Android-added: Added javadocs for newArray(Class, int)
+    // Android-added: Added javadocs for newArray(Class, int).
     /**
      * Returns a new array of the specified component type and length.
      * Equivalent to {@code new componentType[size]}.
@@ -769,7 +769,7 @@
      * @throws NegativeArraySizeException
      *             if {@code size < 0}
      */
-    // Android-changed: Non-native implementation of newArray(Class, int)
+    // Android-changed: Non-native implementation of newArray(Class, int).
     private static Object newArray(Class<?> componentType, int length)
         throws NegativeArraySizeException {
         if (!componentType.isPrimitive()) {
@@ -803,7 +803,7 @@
         throws IllegalArgumentException, NegativeArraySizeException;
     */
 
-    // Android-added: createMultiArray(Class, int[]) method. Used instead of multiNewArray
+    // Android-added: createMultiArray(Class, int[]) method. Used instead of multiNewArray.
     /*
      * Create a multi-dimensional array of objects with the specified type.
      */
diff --git a/ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java b/ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java
index a3c738a..df3b6ed 100644
--- a/ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java
+++ b/ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java
@@ -55,7 +55,7 @@
     protected InetAddress connectedAddress = null;
     private int connectedPort = -1;
 
-    // Android-added: CloseGuard
+    // Android-added: CloseGuard.
     private final CloseGuard guard = CloseGuard.get();
 
     private static final String os = AccessController.doPrivileged(
@@ -67,7 +67,7 @@
      */
     private final static boolean connectDisabled = os.contains("OS X");
 
-    // BEGIN Android-removed: Android doesn't need to load native net library
+    // BEGIN Android-removed: Android doesn't need to load native net library.
     /**
      * Load net library into runtime.
      *
@@ -81,7 +81,7 @@
             });
     }
     */
-    // END Android-removed: Android doesn't need to load native net library
+    // END Android-removed: Android doesn't need to load native net library.
 
     /**
      * Creates a datagram socket
@@ -97,7 +97,7 @@
             throw ioe;
         }
 
-        // Android-added: CloseGuard/fdsan
+        // Android-added: CloseGuard/fdsan.
         if (fd != null && fd.valid()) {
             guard.open("close");
             IoUtils.setFdOwner(fd, this);
@@ -130,7 +130,7 @@
      * @param port the remote port number
      */
     protected void connect(InetAddress address, int port) throws SocketException {
-        // Android-added: BlockGuard
+        // Android-added: BlockGuard.
         BlockGuard.getThreadPolicy().onNetwork();
         connect0(address, port);
         connectedAddress = address;
@@ -248,7 +248,7 @@
      * Close the socket.
      */
     protected void close() {
-        // Android-added: CloseGuard
+        // Android-added: CloseGuard.
         guard.close();
 
         if (fd != null) {
@@ -263,7 +263,7 @@
     }
 
     protected void finalize() {
-        // Android-added: CloseGuard
+        // Android-added: CloseGuard.
         if (guard != null) {
             guard.warnIfOpen();
         }
@@ -375,7 +375,7 @@
             case SO_REUSEADDR:
             case SO_BROADCAST:
                 result = socketGetOption(optID);
-                // Android-added: Added for app compat reason. See methodgetNIFirstAddress
+                // Android-added: Added for app compat reason. See methodgetNIFirstAddress.
                 if (optID == IP_MULTICAST_IF) {
                     return getNIFirstAddress((Integer)result);
                 }
@@ -422,7 +422,7 @@
         return connectDisabled;
     }
 
-    // Android-changed: rewritten on the top of IoBridge
+    // Android-changed: rewritten on the top of IoBridge.
     int dataAvailable() {
         try {
             return IoBridge.available(fd);
diff --git a/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java b/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java
index 0500811..963b2ac 100644
--- a/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java
+++ b/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java
@@ -50,7 +50,7 @@
 {
     /* instance variable for SO_TIMEOUT */
     int timeout;   // timeout in millisec
-    // Android-removed: traffic class is set through socket
+    // Android-removed: traffic class is set through socket.
     // private int trafficClass;
 
     private boolean shut_rd = false;
@@ -63,7 +63,7 @@
     protected int fdUseCount = 0;
 
     /* lock when increment/decrementing fdUseCount */
-    // Android-added: @ReachabilitySensitive
+    // Android-added: @ReachabilitySensitive.
     // Marked mostly because it's used where fd is, and fd isn't declared here.
     // This adds reachabilityFences where we would if fd were annotated.
     @ReachabilitySensitive
@@ -83,7 +83,7 @@
     */
     protected boolean stream;
 
-    // BEGIN Android-removed: Android doesn't need to load native net library
+    // BEGIN Android-removed: Android doesn't need to load native net library.
     /*
     /**
      * Load net library into runtime.
@@ -98,9 +98,9 @@
             });
     }
     */
-    // END Android-removed: Android doesn't need to load native net library
+    // END Android-removed: Android doesn't need to load native net library.
 
-    // Android-added: logs a warning if socket is not closed
+    // Android-added: logs a warning if socket is not closed.
     @ReachabilitySensitive
     private final CloseGuard guard = CloseGuard.get();
 
@@ -112,18 +112,18 @@
         this.stream = stream;
         if (!stream) {
             ResourceManager.beforeUdpCreate();
-            // Android-removed: socketCreate should set fd if it succeeds
+            // Android-removed: socketCreate should set fd if it succeeds.
             // fd = new FileDescriptor();
             try {
                 socketCreate(false);
             } catch (IOException ioe) {
                 ResourceManager.afterUdpClose();
-                // Android-removed: b/26470377 Represent closed sockets with invalid fd, not null.
+                // Android-changed: Closed sockets use an invalid fd, not null. b/26470377
                 // fd = null;
                 throw ioe;
             }
         } else {
-            // Android-removed: socketCreate should set fd if it succeeds
+            // Android-removed: socketCreate should set fd if it succeeds.
             // fd = new FileDescriptor();
             socketCreate(true);
         }
@@ -132,7 +132,7 @@
         if (serverSocket != null)
             serverSocket.setCreated();
 
-        // Android-added: CloseGuard
+        // Android-added: CloseGuard.
         if (fd != null && fd.valid()) {
             guard.open("close");
         }
@@ -301,7 +301,7 @@
         socketSetOption(opt, on, val);
         */
         // END Android-removed: Logic dealing with value type moved to socketSetOption.
-        // Android-added: Keep track of timeout value not handled by socketSetOption
+        // Android-added: Keep track of timeout value not handled by socketSetOption.
         if (opt == SO_TIMEOUT) {
             timeout = (Integer) val;
         }
@@ -385,7 +385,7 @@
         try {
             acquireFD();
             try {
-                // Android-added: BlockGuard
+                // Android-added: BlockGuard.
                 BlockGuard.getThreadPolicy().onNetwork();
                 socketConnect(address, port, timeout);
                 /* socket may have been closed during poll/select */
@@ -446,7 +446,7 @@
     protected void accept(SocketImpl s) throws IOException {
         acquireFD();
         try {
-            // Android-added: BlockGuard
+            // Android-added: BlockGuard.
             BlockGuard.getThreadPolicy().onNetwork();
             socketAccept(s);
         } finally {
@@ -558,10 +558,9 @@
                 if (!stream) {
                     ResourceManager.afterUdpClose();
                 }
-                // Android-changed:
-                // Socket should be untagged before the preclose. After preclose,
-                // socket will dup2-ed to marker_fd, therefore, it won't describe the same file.
-                // If closingPending is true, then the socket has been preclosed.
+                // Android-changed: Socket should be untagged before the preclose.
+                // After preclose, socket will dup2-ed to marker_fd, therefore, it won't describe
+                // the same file.  If closingPending is true, then the socket has been preclosed.
                 //
                 // Also, close the CloseGuard when the #close is called.
                 if (!closePending) {
@@ -582,8 +581,8 @@
                         } finally {
                             socketClose();
                         }
-                        // Android-changed(http://b/26470377): Some Android code doesn't expect file
-                        // descriptor to be null. socketClose invalidates the fd by closing the fd.
+                        // Android-changed: Closed sockets use an invalid fd, not null. b/26470377
+                        // socketClose invalidates the fd by closing the fd.
                         // fd = null;
                         return;
                     } else {
@@ -607,7 +606,7 @@
             // Android-changed: Notified the CloseGuard object as the fd has been released.
             guard.close();
         }
-        // Android-removed: b/26470377 Represent closed sockets with invalid fd, not null.
+        // Android-changed: Closed sockets use an invalid fd, not null. b/26470377
         // fd = null;
         super.reset();
     }
@@ -617,7 +616,7 @@
      * Shutdown read-half of the socket connection;
      */
     protected void shutdownInput() throws IOException {
-      // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+      // Android-changed: Closed sockets use an invalid fd, not null. b/26470377
       if (fd != null && fd.valid()) {
           socketShutdown(SHUT_RD);
           if (socketInputStream != null) {
@@ -631,7 +630,7 @@
      * Shutdown write-half of the socket connection;
      */
     protected void shutdownOutput() throws IOException {
-      // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+      // Android-changed: Closed sockets use an invalid fd, not null. b/26470377
       if (fd != null && fd.valid()) {
           socketShutdown(SHUT_WR);
           shut_wr = true;
@@ -643,7 +642,7 @@
     }
 
     protected void sendUrgentData (int data) throws IOException {
-        // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+        // Android-changed: Closed sockets use an invalid fd, not null. b/26470377
         if (fd == null || !fd.valid()) {
             throw new IOException("Socket Closed");
         }
@@ -654,7 +653,7 @@
      * Cleans up if the user forgets to close it.
      */
     protected void finalize() throws IOException {
-        // Android-added: CloseGuard
+        // Android-added: CloseGuard.
         if (guard != null) {
             guard.warnIfOpen();
         }
@@ -688,8 +687,8 @@
                     try {
                         socketClose();
                     } catch (IOException e) {
-                        // Android-removed: b/26470377 Some Android code doesn't expect file
-                        // descriptor to be null. socketClose invalidates the fd by closing the fd.
+                        // Android-changed: Closed sockets use an invalid fd, not null. b/26470377
+                        // socketClose invalidates the fd by closing the fd.
                         // } finally {
                         //     fd = null;
                     }
@@ -734,7 +733,7 @@
          * close is in progress.
          */
         synchronized (fdLock) {
-            // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+            // Android-changed: Closed sockets use an invalid fd, not null. b/26470377
             if (closePending || (fd == null) || !fd.valid()) {
                 return true;
             } else {
@@ -781,8 +780,8 @@
     abstract void socketShutdown(int howto)
         throws IOException;
 
-    // Android-changed: Method signature changed, socket{Get,Set}Option work directly with Object
-    // values.
+    // Android-changed: Method signature changes.
+    // socket{Get,Set}Option work directly with Object values.
     abstract void socketSetOption(int cmd, Object value) throws SocketException;
     abstract Object socketGetOption(int opt) throws SocketException;
 
diff --git a/ojluni/src/main/java/java/net/CookieManager.java b/ojluni/src/main/java/java/net/CookieManager.java
index dfd3b86..bff9734 100644
--- a/ojluni/src/main/java/java/net/CookieManager.java
+++ b/ojluni/src/main/java/java/net/CookieManager.java
@@ -250,7 +250,7 @@
                 }
             }
         }
-        // Android-added: b/25897688 A fix to return empty map if cookies list is empty
+        // Android-added: A fix to return empty map if cookies list is empty. b/25897688
         if (cookies.isEmpty()) {
             return Collections.emptyMap();
         }
@@ -315,7 +315,7 @@
                                 }
                             }
                             cookie.setPath(path);
-                        // Android-added: b/25763487 A fix to verify cookie URI before removal
+                        // Android-added: A fix to verify cookie URI before removal. b/25763487
                         } else {
                             // Validate existing path
                             if (!pathMatches(uri, cookie)) {
@@ -408,7 +408,7 @@
         return false;
     }
 
-    // Android-changed: b/25763487 Cookie path matching logic in OpenJDK was wrong
+    // Android-changed: Cookie path matching logic in OpenJDK was wrong. b/25763487
     /**
      * Return true iff. the path from {@code cookie} matches the path from {@code uri}.
      */
@@ -436,9 +436,9 @@
     private List<String> sortByPath(List<HttpCookie> cookies) {
         Collections.sort(cookies, new CookiePathComparator());
 
-        // BEGIN Android-changed: Netscape cookie spec and RFC 2965 have different format
-        // of Cookie header; RFC 2965 requires a leading $Version="1" string while Netscape does not
-        // The workaround here is to add a $Version="1" string in advance
+        // BEGIN Android-changed: Cookie header differs in Netscape cookie spec and RFC 2965.
+        // RFC 2965 requires a leading $Version="1" string while Netscape does not.
+        // The workaround here is to add a $Version="1" string in advance.
         final StringBuilder result = new StringBuilder();
         int minVersion = 1;
         for (HttpCookie cookie : cookies) {
@@ -461,7 +461,7 @@
 
         List<String> cookieHeader = new java.util.ArrayList<String>();
         cookieHeader.add(result.toString());
-        // END Android-changed: Netscape cookie spec and RFC 2965 have different format
+        // END Android-changed: Cookie header differs in Netscape cookie spec and RFC 2965.
         return cookieHeader;
     }
 
@@ -475,7 +475,7 @@
             // path rule only applies to the cookies with same name
             if (!c1.getName().equals(c2.getName())) return 0;
 
-            // Android-changed: normalize before comparison
+            // Android-changed: normalize before comparison.
             final String c1Path = normalizePath(c1.getPath());
             final String c2Path = normalizePath(c2.getPath());
 
diff --git a/ojluni/src/main/java/java/net/HttpCookie.java b/ojluni/src/main/java/java/net/HttpCookie.java
index 3ff33c7..70b9b6b 100644
--- a/ojluni/src/main/java/java/net/HttpCookie.java
+++ b/ojluni/src/main/java/java/net/HttpCookie.java
@@ -57,7 +57,7 @@
  * @since 1.6
  */
 public final class HttpCookie implements Cloneable {
-    // BEGIN Android-added: Reserved name can't be HttpCookie name
+    // BEGIN Android-added: Reserved name can't be HttpCookie name.
     private static final Set<String> RESERVED_NAMES = new HashSet<String>();
 
     static {
@@ -73,7 +73,7 @@
         RESERVED_NAMES.add("secure");     // Netscape  RFC 2109  RFC 2965  RFC 6265
         RESERVED_NAMES.add("version");    //           RFC 2109  RFC 2965  RFC 6265
     }
-    // END Android-added: Reserved name can't be HttpCookie name
+    // END Android-added: Reserved name can't be HttpCookie name.
 
     // ---------------- Fields --------------
 
@@ -691,13 +691,13 @@
             String H = host.substring(0, lengthDiff);
             String D = host.substring(lengthDiff);
 
-            // BEGIN Android-changed: App compat reason
+            // BEGIN Android-changed: App compat reason.
             // 1) Disregard RFC 2965 sec. 3.3.2, the "The request-host is a HDN..."
             // 2) match "foo.local" for domain ".local".
             // return (H.indexOf('.') == -1 && D.equalsIgnoreCase(domain));
             return D.equalsIgnoreCase(domain) && ((domain.startsWith(".") && isFullyQualifiedDomainName(domain, 1))
                 || isLocalDomain);
-            // END Android-changed: App compat reason
+            // END Android-changed: App compat reason.
         }
         else if (lengthDiff == -1) {
             // if domain is actually .host
@@ -708,12 +708,12 @@
         return false;
     }
 
-    // BEGIN Android-added: App compat reason
+    // BEGIN Android-added: App compat reason.
     private static boolean isFullyQualifiedDomainName(String s, int firstCharacter) {
         int dotPosition = s.indexOf('.', firstCharacter + 1);
         return dotPosition != -1 && dotPosition < s.length() - 1;
     }
-    // END Android-added: App compat reason
+    // END Android-added: App compat reason.
 
     /**
      * Constructs a cookie header string representation of this cookie,
@@ -799,7 +799,7 @@
     // from RFC 2068, token special case characters
     //
     // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
-    // Android-changed: App compat reason. Disallow "=\t" as token
+    // Android-changed: App compat reason. Disallow "=\t" as token.
     // private static final String tspecials = ",; ";  // deliberately includes space
     private static final String tspecials = ",;= \t";
 
@@ -813,7 +813,7 @@
      *          {@code false} if it is not
      */
     private static boolean isToken(String value) {
-        // Android-added: Reserved name can't be a token
+        // Android-added: Reserved name can't be a token.
         if (RESERVED_NAMES.contains(value.toLowerCase(Locale.US))) {
             return false;
         }
@@ -998,7 +998,7 @@
                         // BEGIN Android-changed: Use HttpDate for date parsing.
                         // it accepts broader set of date formats.
                         // cookie.setMaxAge(cookie.expiryDate2DeltaSeconds(attrValue));
-                        // Android-changed: Altered max age calculation to avoid setting
+                        // Android-changed: Altered max age calculation to avoid setting.
                         // it to MAX_AGE_UNSPECIFIED (-1) if "expires" is one second in past.
                         Date date = HttpDate.parse(attrValue);
                         long maxAgeInSeconds = 0;
@@ -1030,7 +1030,7 @@
         }
     }
 
-    // BEGIN Android-removed: Android doesn't use JavaNetHttpCookieAccess
+    // BEGIN Android-removed: Android doesn't use JavaNetHttpCookieAccess.
     /*
     static {
         sun.misc.SharedSecrets.setJavaNetHttpCookieAccess(
@@ -1046,7 +1046,7 @@
         );
     }
     */
-    // END Android-removed: Android doesn't use JavaNetHttpCookieAccess
+    // END Android-removed: Android doesn't use JavaNetHttpCookieAccess.
 
     /*
      * Returns the original header this cookie was consructed from, if it was
diff --git a/ojluni/src/main/java/java/net/IDN.java b/ojluni/src/main/java/java/net/IDN.java
index a18c3a8..36559cf 100644
--- a/ojluni/src/main/java/java/net/IDN.java
+++ b/ojluni/src/main/java/java/net/IDN.java
@@ -103,7 +103,7 @@
      * @throws IllegalArgumentException   if the input string doesn't conform to RFC 3490 specification
      */
     public static String toASCII(String input, int flag) {
-        // BEGIN Android-changed: Use ICU4J implementation
+        // BEGIN Android-changed: Use ICU4J implementation.
         try {
             return IDNA.convertIDNToASCII(input, flag).toString();
         } catch (android.icu.text.StringPrepParseException e) {
@@ -114,7 +114,7 @@
             }
             throw new IllegalArgumentException("Invalid input to toASCII: " + input, e);
         }
-        // END Android-changed: Use ICU4J implementation
+        // END Android-changed: Use ICU4J implementation.
     }
 
 
@@ -158,7 +158,7 @@
      * @return          the translated {@code String}
      */
     public static String toUnicode(String input, int flag) {
-        // BEGIN Android-changed: Use ICU4J implementation
+        // BEGIN Android-changed: Use ICU4J implementation.
         try {
             // ICU only translates separators to ASCII for toASCII.
             // Java expects the translation for toUnicode too.
@@ -168,10 +168,10 @@
             // the original string is returned.
             return input;
         }
-        // END Android-changed: Use ICU4J implementation
+        // END Android-changed: Use ICU4J implementation.
     }
 
-    // BEGIN Android-added: Use ICU4J implementation
+    // BEGIN Android-added: Use ICU4J implementation.
     private static boolean isLabelSeperator(char c) {
         return (c == '\u3002' || c == '\uff0e' || c == '\uff61');
     }
@@ -184,7 +184,7 @@
         }
         return input;
     }
-    // END Android-added: Use ICU4J implementation
+    // END Android-added: Use ICU4J implementation.
 
     /**
      * Translates a string from ASCII Compatible Encoding (ACE) to Unicode,
diff --git a/ojluni/src/main/java/java/net/InMemoryCookieStore.java b/ojluni/src/main/java/java/net/InMemoryCookieStore.java
index 5df66c0..85aab8b 100644
--- a/ojluni/src/main/java/java/net/InMemoryCookieStore.java
+++ b/ojluni/src/main/java/java/net/InMemoryCookieStore.java
@@ -36,7 +36,7 @@
 import java.util.Iterator;
 import java.util.concurrent.locks.ReentrantLock;
 
-// Android-changed: App compat changes and bug fixes
+// Android-changed: App compat changes and bug fixes.
 // b/26456024 Add targetSdkVersion based compatibility for domain matching
 // b/33034917 Support clearing cookies by adding it with "max-age=0"
 // b/25897688 InMemoryCookieStore ignores scheme (http/https) port and path of the cookie
@@ -52,7 +52,7 @@
  */
 public class InMemoryCookieStore implements CookieStore {
     // the in-memory representation of cookies
-    // BEGIN Android-removed: Remove cookieJar and domainIndex
+    // BEGIN Android-removed: Remove cookieJar and domainIndex.
     /*
     private List<HttpCookie> cookieJar = null;
 
@@ -62,13 +62,13 @@
     //          presence of cookie when retrieve one form index store.
     private Map<String, List<HttpCookie>> domainIndex = null;
     */
-    // END Android-removed: Remove cookieJar and domainIndex
+    // END Android-removed: Remove cookieJar and domainIndex.
     private Map<URI, List<HttpCookie>> uriIndex = null;
 
     // use ReentrantLock instead of syncronized for scalability
     private ReentrantLock lock = null;
 
-    // BEGIN Android-changed: Add targetSdkVersion and remove cookieJar and domainIndex
+    // BEGIN Android-changed: Add targetSdkVersion and remove cookieJar and domainIndex.
     private final boolean applyMCompatibility;
 
     /**
@@ -83,7 +83,7 @@
         lock = new ReentrantLock(false);
         applyMCompatibility = (targetSdkVersion <= 23);
     }
-    // END Android-changed: Add targetSdkVersion and remove cookieJar and domainIndex
+    // END Android-changed: Add targetSdkVersion and remove cookieJar and domainIndex.
 
     /**
      * Add one cookie into cookie store.
@@ -96,8 +96,8 @@
 
         lock.lock();
         try {
-            // Android-changed: http://b/33034917, android supports clearing cookies
-            // by adding the cookie with max-age: 0.
+            // Android-changed: Android supports clearing cookies. http://b/33034917
+            // They are cleared by adding the cookie with max-age: 0.
             //if (cookie.getMaxAge() != 0) {
             addIndex(uriIndex, getEffectiveURI(uri), cookie);
             //}
@@ -121,7 +121,7 @@
         }
 
         List<HttpCookie> cookies = new ArrayList<HttpCookie>();
-        // BEGIN Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // BEGIN Android-changed: InMemoryCookieStore ignores scheme (http/https). b/25897688
         lock.lock();
         try {
             // check domainIndex first
@@ -131,7 +131,7 @@
         } finally {
             lock.unlock();
         }
-        // END Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // END Android-changed: InMemoryCookieStore ignores scheme (http/https). b/25897688
         return cookies;
     }
 
@@ -139,7 +139,7 @@
      * Get all cookies in cookie store, except those have expired
      */
     public List<HttpCookie> getCookies() {
-        // BEGIN Android-changed: Remove cookieJar and domainIndex
+        // BEGIN Android-changed: Remove cookieJar and domainIndex.
         List<HttpCookie> rt = new ArrayList<HttpCookie>();
 
         lock.lock();
@@ -159,7 +159,7 @@
             rt = Collections.unmodifiableList(rt);
             lock.unlock();
         }
-        // END Android-changed: Remove cookieJar and domainIndex
+        // END Android-changed: Remove cookieJar and domainIndex.
 
         return rt;
     }
@@ -213,7 +213,7 @@
             throw new NullPointerException("cookie is null");
         }
 
-        // BEGIN Android-changed: Fix uri not being removed from uriIndex
+        // BEGIN Android-changed: Fix uri not being removed from uriIndex.
         lock.lock();
         try {
             uri = getEffectiveURI(uri);
@@ -230,7 +230,7 @@
         } finally {
             lock.unlock();
         }
-        // END Android-changed: Fix uri not being removed from uriIndex
+        // END Android-changed: Fix uri not being removed from uriIndex.
     }
 
 
@@ -299,7 +299,7 @@
             // need to check H & D component
             String D = host.substring(lengthDiff);
 
-            // Android-changed: b/26456024 targetSdkVersion based compatibility for domain matching
+            // Android-changed: b/26456024 targetSdkVersion based compatibility for domain matching.
             // Android M and earlier: Cookies with domain "foo.com" would not match "bar.foo.com".
             // The RFC dictates that the user agent must treat those domains as if they had a
             // leading period and must therefore match "bar.foo.com".
@@ -319,7 +319,7 @@
 
     private void getInternal1(List<HttpCookie> cookies, Map<URI, List<HttpCookie>> cookieIndex,
             String host) {
-        // BEGIN Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // BEGIN Android-changed: InMemoryCookieStore ignores scheme (http/https). b/25897688
         // Use a separate list to handle cookies that need to be removed so
         // that there is no conflict with iterators.
         ArrayList<HttpCookie> toRemove = new ArrayList<HttpCookie>();
@@ -348,7 +348,7 @@
             }
             toRemove.clear();
         }
-        // END Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // END Android-changed: InMemoryCookieStore ignores scheme (http/https). b/25897688
     }
 
     // @param cookies           [OUT] contains the found cookies
@@ -359,7 +359,7 @@
         void getInternal2(List<HttpCookie> cookies, Map<T, List<HttpCookie>> cookieIndex,
                           T comparator)
     {
-        // BEGIN Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // BEGIN Android-changed: InMemoryCookieStore ignores scheme (http/https). b/25897688
         // Removed cookieJar
         for (T index : cookieIndex.keySet()) {
             if ((index == comparator) || (index != null && comparator.compareTo(index) == 0)) {
@@ -381,7 +381,7 @@
                 } // end of indexedCookies != null
             } // end of comparator.compareTo(index) == 0
         } // end of cookieIndex iteration
-        // END Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // END Android-changed: InMemoryCookieStore ignores scheme (http/https). b/25897688
     }
 
     // add 'cookie' indexed by 'index' into 'indexStore'
@@ -389,9 +389,9 @@
                               T index,
                               HttpCookie cookie)
     {
-        // Android-changed: "index" can be null. We only use the URI based
-        // index on Android and we want to support null URIs. The underlying
-        // store is a HashMap which will support null keys anyway.
+        // Android-changed: "index" can be null.
+        // We only use the URI based index on Android and we want to support null URIs. The
+        // underlying store is a HashMap which will support null keys anyway.
         // if (index != null) {
         List<HttpCookie> cookies = indexStore.get(index);
         if (cookies != null) {
@@ -413,7 +413,7 @@
     //
     private URI getEffectiveURI(URI uri) {
         URI effectiveURI = null;
-        // Android-added: Fix NullPointerException
+        // Android-added: Fix NullPointerException.
         if (uri == null) {
             return null;
         }
diff --git a/ojluni/src/main/java/java/net/Inet4Address.java b/ojluni/src/main/java/java/net/Inet4Address.java
index 1fb7b92..2dc875b 100644
--- a/ojluni/src/main/java/java/net/Inet4Address.java
+++ b/ojluni/src/main/java/java/net/Inet4Address.java
@@ -93,7 +93,7 @@
      *  serialized */
     private static final long serialVersionUID = 3286316764910316507L;
 
-    // BEGIN Android-added: Define special-purpose IPv4 address
+    // BEGIN Android-added: Define special-purpose IPv4 address.
     /** @hide */
     public static final InetAddress ANY = new Inet4Address(null, new byte[] { 0, 0, 0, 0 });
 
@@ -104,10 +104,10 @@
     /** @hide */
     public static final InetAddress LOOPBACK =
             new Inet4Address("localhost", new byte[] { 127, 0, 0, 1 });
-    // END Android-added: Define special-purpose IPv4 address
+    // END Android-added: Define special-purpose IPv4 address.
 
 
-    // BEGIN Android-removed: Android doesn't need to call native init
+    // BEGIN Android-removed: Android doesn't need to call native init.
     /*
      * Perform initializations.
      *
@@ -115,7 +115,7 @@
         init();
     }
     */
-    // END Android-removed: Android doesn't need to call native init
+    // END Android-removed: Android doesn't need to call native init.
     Inet4Address() {
         super();
         holder().hostName = null;
@@ -391,11 +391,11 @@
         return (src[0] & 0xff) + "." + (src[1] & 0xff) + "." + (src[2] & 0xff) + "." + (src[3] & 0xff);
     }
 
-    // BEGIN Android-removed: Android doesn't need to call native init
+    // BEGIN Android-removed: Android doesn't need to call native init.
     /*
      * Perform class load-time initializations.
      *
     private static native void init();
     */
-    // END Android-removed: Android doesn't need to call native init
+    // END Android-removed: Android doesn't need to call native init.
 }
diff --git a/ojluni/src/main/java/java/net/Inet6Address.java b/ojluni/src/main/java/java/net/Inet6Address.java
index c0aadb3..83f3451 100644
--- a/ojluni/src/main/java/java/net/Inet6Address.java
+++ b/ojluni/src/main/java/java/net/Inet6Address.java
@@ -178,15 +178,15 @@
 class Inet6Address extends InetAddress {
     final static int INADDRSZ = 16;
 
-    // BEGIN Android-removed: Remove special handling for link-local addresses
+    // BEGIN Android-removed: Remove special handling for link-local addresses.
     /*
     * cached scope_id - for link-local address use only.
     *
     private transient int cached_scope_id;  // 0
     */
-    // END Android-removed: Remove special handling for link-local addresses
+    // END Android-removed: Remove special handling for link-local addresses.
 
-    // BEGIN Android-added: Define special-purpose IPv6 address
+    // BEGIN Android-added: Define special-purpose IPv6 address.
     /** @hide */
     public static final InetAddress ANY =
             new Inet6Address("::", new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0);
@@ -194,7 +194,7 @@
     /** @hide */
     public static final InetAddress LOOPBACK = new Inet6Address("ip6-localhost",
             new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 0);
-    // END Android-added: Define special-purpose IPv6 address
+    // END Android-added: Define special-purpose IPv6 address.
 
     private class Inet6AddressHolder {
 
@@ -252,7 +252,7 @@
         void init(byte addr[], int scope_id) {
             setAddr(addr);
 
-            // Android-changed: was >= 0
+            // Android-changed: was >= 0.
             if (scope_id > 0) {
                 this.scope_id = scope_id;
                 this.scope_id_set = true;
@@ -272,7 +272,7 @@
             }
         }
 
-        // Android-removed: getnameinfo returns smarter representations than getHostAddress()
+        // Android-removed: getnameinfo returns smarter representations than getHostAddress().
         /*
         String getHostAddress() {
             String s = numericToTextFormat(ipaddress);
@@ -389,11 +389,11 @@
 
     private static final long serialVersionUID = 6880410070516793377L;
 
-    // BEGIN Android-removed: Android doesn't need to call native init
+    // BEGIN Android-removed: Android doesn't need to call native init.
     /*
     // Perform native initialization
     static { init(); }
-    // END Android-removed: Android doesn't need to call native init
+    // END Android-removed: Android doesn't need to call native init.
     */
 
     Inet6Address() {
@@ -622,7 +622,7 @@
         throws IOException, ClassNotFoundException {
         NetworkInterface scope_ifname = null;
 
-        // Android-changed: was getClass().getClassLoader() != null
+        // Android-changed: was getClass().getClassLoader() != null.
         if (getClass().getClassLoader() != Class.class.getClassLoader()) {
             throw new SecurityException ("invalid address type");
         }
@@ -894,7 +894,7 @@
      */
     @Override
     public String getHostAddress() {
-        // Android-changed: getnameinfo returns smarter representations than getHostAddress()
+        // Android-changed: getnameinfo returns smarter representations than getHostAddress().
         // return holder6.getHostAddress();
         return Libcore.os.getnameinfo(this, NI_NUMERICHOST); // Can't throw.
     }
@@ -971,11 +971,11 @@
         return sb.toString();
     }
 
-    // BEGIN Android-removed: Android doesn't need to call native init
+    // BEGIN Android-removed: Android doesn't need to call native init.
     /*
      * Perform class load-time initializations.
      *
     private static native void init();
     */
-    // END Android-removed: Android doesn't need to call native init
+    // END Android-removed: Android doesn't need to call native init.
 }
diff --git a/ojluni/src/main/java/java/net/URLStreamHandler.java b/ojluni/src/main/java/java/net/URLStreamHandler.java
index dffc6d5..c0876e8 100644
--- a/ojluni/src/main/java/java/net/URLStreamHandler.java
+++ b/ojluni/src/main/java/java/net/URLStreamHandler.java
@@ -134,9 +134,9 @@
 
         boolean isRelPath = false;
         boolean queryOnly = false;
-        // BEGIN Android-changed: App compat
+        // BEGIN Android-changed: App compat.
         boolean querySet = false;
-        // END Android-changed: App compat
+        // END Android-changed: App compat.
 
 // FIX: should not assume query if opaque
         // Strip off the query part
@@ -148,22 +148,22 @@
                 if (limit > queryStart)
                     limit = queryStart;
                 spec = spec.substring(0, queryStart);
-                // BEGIN Android-changed: App compat
+                // BEGIN Android-changed: App compat.
                 querySet = true;
-                // END Android-changed: App compat
+                // END Android-changed: App compat.
             }
         }
 
         int i = 0;
         // Parse the authority part if any
-        // BEGIN Android-changed: App compat
+        // BEGIN Android-changed: App compat.
         // boolean isUNCName = (start <= limit - 4) &&
         //                 (spec.charAt(start) == '/') &&
         //                 (spec.charAt(start + 1) == '/') &&
         //                 (spec.charAt(start + 2) == '/') &&
         //                 (spec.charAt(start + 3) == '/');
         boolean isUNCName = false;
-        // END Android-changed: App compat
+        // END Android-changed: App compat.
         if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') &&
             (spec.charAt(start + 1) == '/')) {
             start += 2;
@@ -239,7 +239,7 @@
                     if (ind >= 0) {
                         // port can be null according to RFC2396
                         if (host.length() > (ind + 1)) {
-                            // BEGIN Android-changed: App compat
+                            // BEGIN Android-changed: App compat.
                             // port = Integer.parseInt(host.substring(ind + 1));
                             char firstPortChar = host.charAt(ind+1);
                             if (firstPortChar >= '0' && firstPortChar <= '9') {
@@ -248,7 +248,7 @@
                                 throw new IllegalArgumentException("invalid port: " +
                                                                    host.substring(ind + 1));
                             }
-                            // END Android-changed: App compat
+                            // END Android-changed: App compat.
                         }
                         host = host.substring(0, ind);
                     }
@@ -263,14 +263,14 @@
 
             // If the authority is defined then the path is defined by the
             // spec only; See RFC 2396 Section 5.2.4.
-            // BEGIN Android-changed: App compat
+            // BEGIN Android-changed: App compat.
             // if (authority != null && authority.length() > 0)
             //   path = "";
             path = null;
             if (!querySet) {
                 query = null;
             }
-            // END Android-changed: App compat
+            // END Android-changed: App compat.
         }
 
         if (host == null) {
@@ -297,21 +297,21 @@
                 path = seperator + spec.substring(start, limit);
             }
         }
-        // BEGIN Android-changed: App compat
+        // BEGIN Android-changed: App compat.
         //else if (queryOnly && path != null) {
         //    int ind = path.lastIndexOf('/');
         //    if (ind < 0)
         //        ind = 0;
         //    path = path.substring(0, ind) + "/";
         //}
-        // END Android-changed: App compat
+        // END Android-changed: App compat.
         if (path == null)
             path = "";
 
-        // BEGIN Android-changed
+        // BEGIN Android-changed: always assume isRelPath is true.
         //if (isRelPath) {
         if (true) {
-        // END Android-changed
+        // END Android-changed: always assume isRelPath is true.
             // Remove embedded /./
             while ((i = path.indexOf("/./")) >= 0) {
                 path = path.substring(0, i) + path.substring(i + 2);
@@ -319,21 +319,21 @@
             // Remove embedded /../ if possible
             i = 0;
             while ((i = path.indexOf("/../", i)) >= 0) {
-                // BEGIN Android-changed: App compat
+                // BEGIN Android-changed: App compat.
                 /*
                  * Trailing /../
                  */
                 if (i == 0) {
                     path = path.substring(i + 3);
                     i = 0;
-                // END Android-changed: App compat
+                // END Android-changed: App compat.
                 /*
                  * A "/../" will cancel the previous segment and itself,
                  * unless that segment is a "/../" itself
                  * i.e. "/a/b/../c" becomes "/a/c"
                  * but "/../../a" should stay unchanged
                  */
-                // Android-changed: App compat
+                // Android-changed: App compat.
                 // if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
                 } else if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
                     (path.indexOf("/../", limit) != 0)) {
@@ -360,7 +360,7 @@
             if (path.endsWith("/."))
                 path = path.substring(0, path.length() -1);
 
-            // Android-changed: App compat: Remove trailing ?
+            // Android-changed: App compat: Remove trailing '?'.
             if (path.endsWith("?"))
                 path = path.substring(0, path.length() -1);
         }
@@ -391,7 +391,7 @@
      * @since 1.3
      */
     protected boolean equals(URL u1, URL u2) {
-        // Android-changed: Avoid network I/O
+        // Android-changed: Avoid network I/O.
         return Objects.equals(u1.getRef(), u2.getRef()) &&
                Objects.equals(u1.getQuery(), u2.getQuery()) &&
                // sameFile compares the protocol, file, port & host components of
@@ -408,7 +408,7 @@
      * @since 1.3
      */
     protected int hashCode(URL u) {
-        // Android-changed: Avoid network I/O
+        // Android-changed: Avoid network I/O.
         // Hash on the same set of fields that we compare in equals().
         return Objects.hash(
                 u.getRef(),
@@ -522,7 +522,7 @@
         if (u.getRef() != null)
             len += 1 + u.getRef().length();
 
-        // BEGIN Android-changed: Add a toExternalForm variant that optionally escapes illegal chars
+        // BEGIN Android-changed: New toExternalForm variant that optionally escapes illegal chars.
         // TODO: The variant has been removed. We can potentially revert the change
         StringBuilder result = new StringBuilder(len);
         result.append(u.getProtocol());
@@ -535,7 +535,7 @@
         if (fileAndQuery != null) {
             result.append(fileAndQuery);
         }
-        // END Android-changed: Add a toExternalForm variant that optionally escapes illegal chars
+        // END Android-changed: New toExternalForm variant that optionally escapes illegal chars.
         if (u.getRef() != null) {
             result.append("#");
             result.append(u.getRef());
@@ -543,7 +543,7 @@
         return result.toString();
     }
 
-    // Android-changed: Removed @see tag (target is package-private):
+    // Android-changed: Removed @see tag (target is package-private).
     // @see     java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)
     /**
      * Sets the fields of the {@code URL} argument to the indicated values.
diff --git a/ojluni/src/main/java/java/security/Provider.java b/ojluni/src/main/java/java/security/Provider.java
index 9936859..6deb954 100644
--- a/ojluni/src/main/java/java/security/Provider.java
+++ b/ojluni/src/main/java/java/security/Provider.java
@@ -95,7 +95,7 @@
     // Declare serialVersionUID to be compatible with JDK1.1
     static final long serialVersionUID = -4298000515446427739L;
 
-    // Android-added: Provider registration
+    // Android-added: Provider registration.
     // Marking a provider as "registered" makes it change the security version when
     // changes to it are made.  As of 2017-05-22 this is only used in ProviderTest.
     // TODO: Change ProviderTest to no longer require this mechanism
@@ -703,7 +703,7 @@
 
     private void readObject(ObjectInputStream in)
                 throws IOException, ClassNotFoundException {
-        // Android-added: Provider registration
+        // Android-added: Provider registration.
         registered = false;
         Map<Object,Object> copy = new HashMap<>();
         for (Map.Entry<Object,Object> entry : super.entrySet()) {
@@ -717,7 +717,7 @@
     }
 
     private boolean checkLegacy(Object key) {
-        // Android-added: Provider registration
+        // Android-added: Provider registration.
         if (registered) {
             Security.increaseVersion();
         }
@@ -742,7 +742,7 @@
         for (Map.Entry<?,?> e : t.entrySet()) {
             implPut(e.getKey(), e.getValue());
         }
-        // Android-added: Provider registration
+        // Android-added: Provider registration.
         if (registered) {
             Security.increaseVersion();
         }
@@ -817,7 +817,7 @@
             if (!checkLegacy(key)) {
                 return null;
             }
-            // BEGIN Android-changed: use compute() instead of computeIfAbsent() to avoid cast fails
+            // BEGIN Android-changed: use compute(), not computeIfAbsent(), to avoid cast fails.
             // The upstream code cannot ever succeed as the cast from BiFunction to Function
             // always fails.
             // legacyStrings.computeIfAbsent((String) key,
@@ -825,7 +825,7 @@
             legacyStrings.compute((String) key,
                     (BiFunction<? super String, ? super String, ? extends String>)
                             remappingFunction);
-            // END Android-changed: use compute() instead of computeIfAbsent() to avoid cast fails
+            // END Android-changed: use compute(), not computeIfAbsent(), to avoid cast fails.
         }
         return super.compute(key, remappingFunction);
     }
@@ -887,7 +887,7 @@
         serviceSet = null;
         super.clear();
         putId();
-        // Android-added: Provider registration
+        // Android-added: Provider registration.
         if (registered) {
           Security.increaseVersion();
         }
@@ -1192,7 +1192,7 @@
             String key = type + "." + algorithm + " " + entry.getKey();
             super.put(key, entry.getValue());
         }
-        // Android-added: Provider registration
+        // Android-added: Provider registration.
         if (registered) {
             Security.increaseVersion();
         }
@@ -1214,7 +1214,7 @@
             String key = type + "." + algorithm + " " + entry.getKey();
             super.remove(key);
         }
-        // Android-added: Provider registration
+        // Android-added: Provider registration.
         if (registered) {
           Security.increaseVersion();
         }
@@ -1883,7 +1883,7 @@
 
     }
 
-    // BEGIN Android-added: Provider registration
+    // BEGIN Android-added: Provider registration.
     /**
      * @hide
      */
@@ -1922,5 +1922,5 @@
         // stored field, if the services didn't change in the meantime.
         getServices();
     }
-    // END Android-added: Provider registration
+    // END Android-added: Provider registration.
 }
diff --git a/ojluni/src/main/java/java/text/DateFormatSymbols.java b/ojluni/src/main/java/java/text/DateFormatSymbols.java
index 97dc528..5f48e1b 100644
--- a/ojluni/src/main/java/java/text/DateFormatSymbols.java
+++ b/ojluni/src/main/java/java/text/DateFormatSymbols.java
@@ -101,7 +101,7 @@
  */
 public class DateFormatSymbols implements Serializable, Cloneable {
 
-    // Android-changed: Removed reference to DateFormatSymbolsProvider but suggested getInstance()
+    // Android-changed: Removed reference to DateFormatSymbolsProvider but suggested getInstance().
     // be used instead in case Android supports it in future.
     /**
      * Construct a DateFormatSymbols object by loading format data from
@@ -123,7 +123,7 @@
         initializeData(Locale.getDefault(Locale.Category.FORMAT));
     }
 
-    // Android-changed: Removed reference to DateFormatSymbolsProvider but suggested getInstance()
+    // Android-changed: Removed reference to DateFormatSymbolsProvider but suggested getInstance().
     // be used instead in case Android supports it in future.
     /**
      * Construct a DateFormatSymbols object by loading format data from
@@ -229,7 +229,7 @@
      * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
      * All locales use the same these unlocalized pattern characters.
      */
-    // Android-changed: Add 'c' (standalone day of week), 'b' (day period),
+    // Android-changed: Add 'c' (standalone day of week), 'b' (day period),.
     //   'B' (flexible day period)
     static final String  patternChars = "GyMdkHmsSEDFwWahKzZYuXLcbB";
 
@@ -258,7 +258,7 @@
     static final int PATTERN_MONTH_STANDALONE     = 22; // L
     // Android-added: Constant for standalone day of week.
     static final int PATTERN_STANDALONE_DAY_OF_WEEK = 23; // c
-    // Android-added: Constant for pattern letter 'b', 'B'
+    // Android-added: Constant for pattern letter 'b', 'B'.
     static final int PATTERN_DAY_PERIOD = 24; // b
     static final int PATTERN_FLEXIBLE_DAY_PERIOD = 25; // B
 
@@ -844,7 +844,7 @@
         // END Android-changed: Use ICU data and move cache handling to getCachedInstance().
     }
 
-    // Android-removed: toOneBasedArray(String[])
+    // Android-removed: toOneBasedArray(String[]).
 
     // BEGIN Android-added: initializeSupplementaryData(LocaleData) for tiny and standalone fields.
     private void initializeSupplementaryData(LocaleData localeData) {
@@ -917,10 +917,11 @@
         }
         return zoneStrings;
     }
+    // END Android-changed: extract initialization of zoneStrings to separate method.
 
     private String[][] getZoneStringsImpl(boolean needsCopy) {
+        // Android-changed: use helper method to initialize zoneStrings.
         String[][] zoneStrings = internalZoneStrings();
-        // END Android-changed: extract initialization of zoneStrings to separate method.
 
         if (!needsCopy) {
             return zoneStrings;
diff --git a/ojluni/src/main/java/java/util/Arrays.java b/ojluni/src/main/java/java/util/Arrays.java
index 6da3e5d..8cd8aaf 100644
--- a/ojluni/src/main/java/java/util/Arrays.java
+++ b/ojluni/src/main/java/java/util/Arrays.java
@@ -78,7 +78,7 @@
      * tasks that makes parallel speedups unlikely.
      * @hide
      */
-    // Android-changed: Make MIN_ARRAY_SORT_GRAN public and @hide (used by harmony ArraysTest)
+    // Android-changed: Make MIN_ARRAY_SORT_GRAN public and @hide (used by harmony ArraysTest).
     public static final int MIN_ARRAY_SORT_GRAN = 1 << 13;
 
     // Suppresses default constructor, ensuring non-instantiability.
@@ -1232,14 +1232,14 @@
      *         {@link Comparable} contract
      */
     public static void sort(Object[] a) {
-        // Android-removed: LegacyMergeSort support
+        // Android-removed: LegacyMergeSort support.
         // if (LegacyMergeSort.userRequested)
         //     legacyMergeSort(a);
         // else
             ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
     }
 
-    // Android-removed: legacyMergeSort() (unused on Android)
+    // Android-removed: legacyMergeSort() (unused on Android).
 
     /**
      * Sorts the specified range of the specified array of objects into
@@ -1295,14 +1295,14 @@
      */
     public static void sort(Object[] a, int fromIndex, int toIndex) {
         rangeCheck(a.length, fromIndex, toIndex);
-        // Android-removed: LegacyMergeSort support
+        // Android-removed: LegacyMergeSort support.
         // if (LegacyMergeSort.userRequested)
         //     legacyMergeSort(a, fromIndex, toIndex);
         // else
             ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
     }
 
-    // Android-removed: legacyMergeSort() (unused on Android)
+    // Android-removed: legacyMergeSort() (unused on Android).
 
     /**
      * Tuning parameter: list size at or below which insertion sort will be
@@ -1417,7 +1417,7 @@
         if (c == null) {
             sort(a);
         } else {
-        // Android-removed: LegacyMergeSort support
+        // Android-removed: LegacyMergeSort support.
             // if (LegacyMergeSort.userRequested)
             //     legacyMergeSort(a, c);
             // else
@@ -1425,7 +1425,7 @@
         }
     }
 
-    // Android-removed: legacyMergeSort() (unused on Android)
+    // Android-removed: legacyMergeSort() (unused on Android).
 
     /**
      * Sorts the specified range of the specified array of objects according
@@ -1485,7 +1485,7 @@
             sort(a, fromIndex, toIndex);
         } else {
             rangeCheck(a.length, fromIndex, toIndex);
-            // Android-removed: LegacyMergeSort support
+            // Android-removed: LegacyMergeSort support.
             // if (LegacyMergeSort.userRequested)
             //     legacyMergeSort(a, fromIndex, toIndex, c);
             // else
@@ -1493,8 +1493,8 @@
         }
     }
 
-    // Android-removed: legacyMergeSort() (unused on Android)
-    // Android-removed: mergeSort() (unused on Android)
+    // Android-removed: legacyMergeSort() (unused on Android).
+    // Android-removed: mergeSort() (unused on Android).
 
     // Parallel prefix
 
@@ -4110,7 +4110,7 @@
 
         for (Object element : a) {
             int elementHash = 0;
-            // BEGIN Android-changed: getComponentType() is faster than instanceof()
+            // BEGIN Android-changed: getComponentType() is faster than instanceof().
             if (element != null) {
                 Class<?> cl = element.getClass().getComponentType();
                 if (cl == null)
@@ -4136,7 +4136,7 @@
                 else
                     elementHash = element.hashCode();
             }
-            // END Android-changed: getComponentType() is faster than instanceof()
+            // END Android-changed: getComponentType() is faster than instanceof().
             result = 31 * result + elementHash;
         }
 
diff --git a/ojluni/src/main/java/java/util/Calendar.java b/ojluni/src/main/java/java/util/Calendar.java
index 3a0343b..a5be988 100644
--- a/ojluni/src/main/java/java/util/Calendar.java
+++ b/ojluni/src/main/java/java/util/Calendar.java
@@ -1595,7 +1595,7 @@
      */
     protected Calendar(TimeZone zone, Locale aLocale)
     {
-        // BEGIN Android-added: Allow aLocale == null
+        // BEGIN Android-added: Allow aLocale == null.
         // http://b/16938922.
         //
         // TODO: This is for backwards compatibility only. Seems like a better idea to throw
@@ -1603,7 +1603,7 @@
         if (aLocale == null) {
             aLocale = Locale.getDefault();
         }
-        // END Android-added: Allow aLocale == null
+        // END Android-added: Allow aLocale == null.
         fields = new int[FIELD_COUNT];
         isSet = new boolean[FIELD_COUNT];
         stamp = new int[FIELD_COUNT];
@@ -1667,7 +1667,7 @@
         return createCalendar(zone, aLocale);
     }
 
-    // BEGIN Android-added: add getJapaneseImperialInstance()
+    // BEGIN Android-added: add getJapaneseImperialInstance().
     /**
      * Create a Japanese Imperial Calendar.
      * @hide
@@ -1675,14 +1675,14 @@
     public static Calendar getJapaneseImperialInstance(TimeZone zone, Locale aLocale) {
         return new JapaneseImperialCalendar(zone, aLocale);
     }
-    // END Android-added: add getJapaneseImperialInstance()
+    // END Android-added: add getJapaneseImperialInstance().
 
     private static Calendar createCalendar(TimeZone zone,
                                            Locale aLocale)
     {
-        // BEGIN Android-changed: only support GregorianCalendar here
+        // BEGIN Android-changed: only support GregorianCalendar here.
         return new GregorianCalendar(zone, aLocale);
-        // END Android-changed: only support GregorianCalendar here
+        // END Android-changed: only support GregorianCalendar here.
     }
 
     /**
@@ -2061,13 +2061,13 @@
      * @since 1.6
      */
     public String getDisplayName(int field, int style, Locale locale) {
-        // BEGIN Android-changed: Treat ALL_STYLES as SHORT
+        // BEGIN Android-changed: Treat ALL_STYLES as SHORT.
         // Android has traditionally treated ALL_STYLES as SHORT, even though
         // it's not documented to be a valid value for style.
         if (style == ALL_STYLES) {
             style = SHORT;
         }
-        // END Android-changed: Treat ALL_STYLES as SHORT
+        // END Android-changed: Treat ALL_STYLES as SHORT.
         if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
                             ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
             return null;
@@ -2161,7 +2161,7 @@
                                     ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
             return null;
         }
-        // Android-added: Add complete() here to fix leniency, see http://b/35382060
+        // Android-added: Add complete() here to fix leniency. http://b/35382060
         complete();
 
         String calendarType = getCalendarType();
@@ -2209,12 +2209,12 @@
             baseStyle < minStyle || baseStyle > maxStyle) {
             throw new IllegalArgumentException();
         }
-        // BEGIN Android-added: Check for invalid baseStyle == 3
+        // BEGIN Android-added: Check for invalid baseStyle == 3.
         // 3 is not a valid base style (unlike 1, 2 and 4). Throw if used.
         if (baseStyle == 3) {
             throw new IllegalArgumentException();
         }
-        // END Android-added: Check for invalid baseStyle == 3
+        // END Android-added: Check for invalid baseStyle == 3.
         if (locale == null) {
             throw new NullPointerException();
         }
@@ -2574,12 +2574,12 @@
         return style & ~STANDALONE_MASK;
     }
 
-    // BEGIN Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat
+    // BEGIN Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat.
     /**
      * @hide
      */
     public static int toStandaloneStyle(int style) {
-    // END Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat
+    // END Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat.
         return style | STANDALONE_MASK;
     }
 
diff --git a/ojluni/src/main/java/java/util/GregorianCalendar.java b/ojluni/src/main/java/java/util/GregorianCalendar.java
index 1d8c87b..46733e9 100644
--- a/ojluni/src/main/java/java/util/GregorianCalendar.java
+++ b/ojluni/src/main/java/java/util/GregorianCalendar.java
@@ -739,12 +739,12 @@
         gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
     }
 
-    // BEGIN Android-added
+    // BEGIN Android-added: Constructor.
     GregorianCalendar(long milliseconds) {
         this();
         setTimeInMillis(milliseconds);
     }
-    // END Android-added
+    // END Android-added: Constructor.
 
 /////////////////
 // Public methods
@@ -1080,7 +1080,7 @@
             }
 
             fd += delta; // fd is the expected fixed date after the calculation
-            // BEGIN Android-changed: time zone related calculation via helper methods
+            // BEGIN Android-changed: time zone related calculation via helper methods.
             // Calculate the time in the UTC time zone.
             long utcTime = (fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
 
@@ -1093,7 +1093,7 @@
 
             // Update the time and recompute the fields.
             setTimeInMillis(millis);
-            // END Android-changed: time zone related calculation via helper methods
+            // END Android-changed: time zone related calculation via helper methods.
         }
     }
 
@@ -2346,12 +2346,12 @@
         }
         if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
             if (tz instanceof ZoneInfo) {
-                // BEGIN Android-changed: use libcore.util.ZoneInfo
+                // BEGIN Android-changed: use libcore.util.ZoneInfo.
                 // The method name to get offsets differs from sun.util.calendar.ZoneInfo
                 // zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
                 ZoneInfo zoneInfo = (ZoneInfo) tz;
                 zoneOffset = zoneInfo.getOffsetsByUtcTime(time, zoneOffsets);
-                // END Android-changed: use libcore.util.ZoneInfo
+                // END Android-changed: use libcore.util.ZoneInfo.
             } else {
                 zoneOffset = tz.getOffset(time);
                 zoneOffsets[0] = tz.getRawOffset();
@@ -2801,11 +2801,11 @@
         // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
         // or DST_OFFSET fields; then we use those fields.
         TimeZone zone = getZone();
-        // BEGIN Android-changed: time zone related calculation via helper methods
+        // BEGIN Android-changed: time zone related calculation via helper methods.
         int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
 
         millis = adjustForZoneAndDaylightSavingsTime(tzMask, millis, zone);
-        // END Android-changed: time zone related calculation via helper methods
+        // END Android-changed: time zone related calculation via helper methods.
 
         // Set this calendar's time in milliseconds
         time = millis;
@@ -2828,7 +2828,7 @@
         setFieldsNormalized(mask);
     }
 
-    // BEGIN Android-added: helper methods for time zone related calculation
+    // BEGIN Android-added: helper methods for time zone related calculation.
     /**
      * Calculates the time in milliseconds that this calendar represents using the UTC time,
      * timezone information (specifically Daylight Savings Time (DST) rules, if any) and knowledge
@@ -2998,7 +2998,7 @@
         }
         return dstOffset;
     }
-    // END Android-added: helper methods for time zone related calculation
+    // END Android-added: helper methods for time zone related calculation.
 
     /**
      * Computes the fixed date under either the Gregorian or the
diff --git a/ojluni/src/main/java/java/util/TreeMap.java b/ojluni/src/main/java/java/util/TreeMap.java
index 20d98bc..3359635 100644
--- a/ojluni/src/main/java/java/util/TreeMap.java
+++ b/ojluni/src/main/java/java/util/TreeMap.java
@@ -1343,7 +1343,7 @@
      */
     abstract static class NavigableSubMap<K,V> extends AbstractMap<K,V>
         implements NavigableMap<K,V>, java.io.Serializable {
-        // Android-changed: Explicitly add a serialVersionUID so that we're serialization
+        // Android-changed: Explicitly add a serialVersionUID so that we're serialization.
         // compatible with the Java-7 version of this class. Several new methods were added
         // in Java-8 but none of them have any bearing on the serialized format of the class
         // or require any additional state to be preserved.
@@ -1877,11 +1877,11 @@
         }
 
         public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
-            // BEGIN Android-changed: Fix for edge cases
+            // BEGIN Android-changed: Fix for edge cases.
             // if (!inRange(toKey, inclusive))
             if (!inRange(toKey) && !(!toEnd && m.compare(toKey, hi) == 0 &&
                 !hiInclusive && !inclusive))
-            // END Android-changed: Fix for edge cases
+            // END Android-changed: Fix for edge cases.
                 throw new IllegalArgumentException("toKey out of range");
             return new AscendingSubMap<>(m,
                                          fromStart, lo,    loInclusive,
@@ -1889,11 +1889,11 @@
         }
 
         public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
-            // BEGIN Android-changed: Fix for edge cases
+            // BEGIN Android-changed: Fix for edge cases.
             // if (!inRange(fromKey, inclusive))
             if (!inRange(fromKey) && !(!fromStart && m.compare(fromKey, lo) == 0 &&
                 !loInclusive && !inclusive))
-            // END Android-changed: Fix for edge cases
+            // END Android-changed: Fix for edge cases.
                 throw new IllegalArgumentException("fromKey out of range");
             return new AscendingSubMap<>(m,
                                          false, fromKey, inclusive,
@@ -1970,11 +1970,11 @@
         }
 
         public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
-            // BEGIN Android-changed: Fix for edge cases
+            // BEGIN Android-changed: Fix for edge cases.
             // if (!inRange(toKey, inclusive))
             if (!inRange(toKey) && !(!fromStart && m.compare(toKey, lo) == 0 &&
                 !loInclusive && !inclusive))
-            // END Android-changed: Fix for edge cases
+            // END Android-changed: Fix for edge cases.
                 throw new IllegalArgumentException("toKey out of range");
             return new DescendingSubMap<>(m,
                                           false, toKey, inclusive,
@@ -1982,11 +1982,11 @@
         }
 
         public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
-            // BEGIN Android-changed: Fix for edge cases
+            // BEGIN Android-changed: Fix for edge cases.
             // if (!inRange(fromKey, inclusive))
             if (!inRange(fromKey) && !(!toEnd && m.compare(fromKey, hi) == 0 &&
                 !hiInclusive && !inclusive))
-            // END Android-changed: Fix for edge cases
+            // END Android-changed: Fix for edge cases.
                 throw new IllegalArgumentException("fromKey out of range");
             return new DescendingSubMap<>(m,
                                           fromStart, lo, loInclusive,
diff --git a/ojluni/src/main/java/java/util/zip/ZipFile.java b/ojluni/src/main/java/java/util/zip/ZipFile.java
index 851aab1..e06fb6d 100644
--- a/ojluni/src/main/java/java/util/zip/ZipFile.java
+++ b/ojluni/src/main/java/java/util/zip/ZipFile.java
@@ -81,7 +81,7 @@
     private final boolean locsig;  // if zip file starts with LOCSIG (usually true)
     private volatile boolean closeRequested = false;
 
-    // Android-added: CloseGuard support
+    // Android-added: CloseGuard support.
     private final CloseGuard guard = CloseGuard.get();
 
     // Android-added: Do not use unlink() to implement OPEN_DELETE.
@@ -243,7 +243,7 @@
                                                Integer.toHexString(mode));
         }
         String name = file.getPath();
-        // Android-removed: SecurityManager is always null
+        // Android-removed: SecurityManager is always null.
         /*
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
@@ -260,16 +260,16 @@
         if (charset == null)
             throw new NullPointerException("charset is null");
         this.zc = ZipCoder.get(charset);
-        // Android-removed: Skip perf counters
+        // Android-removed: Skip perf counters.
         // long t0 = System.nanoTime();
         jzfile = open(name, mode, file.lastModified(), usemmap);
-        // Android-removed: Skip perf counters
+        // Android-removed: Skip perf counters.
         // sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
         // sun.misc.PerfCounter.getZipFileCount().increment();
         this.name = name;
         this.total = getTotal(jzfile);
         this.locsig = startsWithLOC(jzfile);
-        // Android-added: CloseGuard support
+        // Android-added: CloseGuard support.
         guard.open("close");
     }
 
@@ -668,7 +668,7 @@
     public void close() throws IOException {
         if (closeRequested)
             return;
-        // Android-added: CloseGuard support
+        // Android-added: CloseGuard support.
         if (guard != null) {
             guard.close();
         }
@@ -739,7 +739,7 @@
      * @see    java.util.zip.ZipFile#close()
      */
     protected void finalize() throws IOException {
-        // Android-added: CloseGuard support
+        // Android-added: CloseGuard support.
         if (guard != null) {
             guard.warnIfOpen();
         }
diff --git a/ojluni/src/main/java/sun/misc/SharedSecrets.java b/ojluni/src/main/java/sun/misc/SharedSecrets.java
index 45cd489..226dbf7 100644
--- a/ojluni/src/main/java/sun/misc/SharedSecrets.java
+++ b/ojluni/src/main/java/sun/misc/SharedSecrets.java
@@ -35,7 +35,7 @@
     for this purpose, namely the loss of compile-time checking. */
 
 public class SharedSecrets {
-    // BEGIN Android-removed: Pruned unused access interfaces
+    // BEGIN Android-removed: Pruned unused access interfaces.
     /*
     private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static JavaUtilJarAccess javaUtilJarAccess;
@@ -46,9 +46,9 @@
     private static JavaNetHttpCookieAccess javaNetHttpCookieAccess;
     private static JavaNioAccess javaNioAccess;
     */
-    // END Android-removed: Pruned unused access interfaces
+    // END Android-removed: Pruned unused access interfaces.
     private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
-    // BEGIN Android-removed: Pruned unused access interfaces
+    // BEGIN Android-removed: Pruned unused access interfaces.
     /*
     private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess;
     private static JavaSecurityAccess javaSecurityAccess;
@@ -129,7 +129,7 @@
         return javaIOAccess;
     }
     */
-    // END Android-removed: Pruned unused access interfaces
+    // END Android-removed: Pruned unused access interfaces.
 
     public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiofda) {
         javaIOFileDescriptorAccess = jiofda;
@@ -150,7 +150,7 @@
         return javaIOFileDescriptorAccess;
     }
 
-    // BEGIN Android-removed: Pruned unused access interfaces
+    // BEGIN Android-removed: Pruned unused access interfaces.
     /*
     public static void setJavaOISAccess(JavaOISAccess access) {
         javaOISAccess = access;
@@ -221,5 +221,5 @@
         javaObjectInputStreamAccess = access;
     }
     */
-    // END Android-removed: Pruned unused access interfaces
+    // END Android-removed: Pruned unused access interfaces.
 }
diff --git a/ojluni/src/main/java/sun/misc/URLClassPath.java b/ojluni/src/main/java/sun/misc/URLClassPath.java
index e9a89bc..0961d7a 100644
--- a/ojluni/src/main/java/sun/misc/URLClassPath.java
+++ b/ojluni/src/main/java/sun/misc/URLClassPath.java
@@ -360,7 +360,7 @@
         lookupCacheEnabled = false;
     }
 
-    // BEGIN Android-changed: No lookup chache support
+    // BEGIN Android-changed: No lookup cache support.
     /*
     private static native URL[] getLookupCacheURLs(ClassLoader loader);
     private static native int[] getLookupCacheForClassLoader(ClassLoader loader,
@@ -380,7 +380,7 @@
                                             String className) {
         return false;
     }
-    // END Android-changed: No lookup chache support
+    // END Android-changed: No lookup cache support.
 
 
     synchronized boolean knownToNotExist(String className) {
@@ -816,7 +816,7 @@
         private final HashMap<String, Loader> lmap;
         private final AccessControlContext acc;
         private boolean closed = false;
-        // Android-changed: Not needed, called directly
+        // Android-changed: Not needed, called directly.
         // private static final sun.misc.JavaUtilZipFileAccess zipAccess =
         //      sun.misc.SharedSecrets.getJavaUtilZipFileAccess();
 
diff --git a/ojluni/src/main/java/sun/misc/VM.java b/ojluni/src/main/java/sun/misc/VM.java
index f9060ba..0c5c4e5 100644
--- a/ojluni/src/main/java/sun/misc/VM.java
+++ b/ojluni/src/main/java/sun/misc/VM.java
@@ -93,7 +93,7 @@
         return STATE_GREEN;
     }
 
-    // Android-removed: Not used
+    // Android-removed: Not used.
     /** @deprecated */
     // @Deprecated
     // public static void registerVMNotification(VMNotification n) { }
@@ -233,7 +233,7 @@
         return allowArraySyntax;
     }
 
-    // BEGIN Android-removed: Not used on android
+    // BEGIN Android-removed: Not used on android.
     /**
      * Returns true if the given class loader is in the system domain
      * in which all permissions are granted.
@@ -241,7 +241,7 @@
     // public static boolean isSystemDomainLoader(ClassLoader loader) {
     //     return loader == null;
     // }
-    // END Android-removed: Not used on android
+    // END Android-removed: Not used on android.
 
     /**
      * Returns the system property of the specified key saved at
@@ -403,7 +403,7 @@
     private final static int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010;
     private final static int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020;
 
-    // BEGIN Android-removed: latestUserDefinedLoader()/initialize() not supported
+    // BEGIN Android-removed: latestUserDefinedLoader()/initialize() not supported.
     // /*
     //  * Returns the first non-null class loader up the execution stack,
     //  * or null if only code from the null class loader is on the stack.
@@ -414,5 +414,5 @@
     //     initialize();
     // }
     // private native static void initialize();
-    // END Android-removed: latestUserDefinedLoader()/initialize() not supported
+    // END Android-removed: latestUserDefinedLoader()/initialize() not supported.
 }
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/reflect/misc/ReflectUtil.java b/ojluni/src/main/java/sun/reflect/misc/ReflectUtil.java
index b4fdf70..6af86d5 100644
--- a/ojluni/src/main/java/sun/reflect/misc/ReflectUtil.java
+++ b/ojluni/src/main/java/sun/reflect/misc/ReflectUtil.java
@@ -116,7 +116,7 @@
         return false;
     }
 
-    // Android-removed: Dead code: Unused method conservativeCheckMemberAccess()
+    // Android-removed: Dead code: Unused method conservativeCheckMemberAccess().
 
     /**
      * Checks package access on the given class.
@@ -262,6 +262,6 @@
         return Proxy.isProxyClass(cls) && !pkg.isEmpty();
     }
 
-    // Android-removed: Dead code: unused method checkProxyMethod()
-    // Android-removed: Dead code: unused method isVMAnonymousClass()
+    // Android-removed: Dead code: unused method checkProxyMethod().
+    // Android-removed: Dead code: unused method isVMAnonymousClass().
 }
diff --git a/ojluni/src/main/java/sun/security/util/DerInputStream.java b/ojluni/src/main/java/sun/security/util/DerInputStream.java
index 6608676..7f42bb0 100644
--- a/ojluni/src/main/java/sun/security/util/DerInputStream.java
+++ b/ojluni/src/main/java/sun/security/util/DerInputStream.java
@@ -325,7 +325,7 @@
      *          (used to initialize an auto-growing data structure)
      * @return array of the values in the sequence
      */
-    // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation
+    // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation.
     public DerValue[] getSequence(int startLen,
             boolean originalEncodedFormRetained) throws IOException {
         tag = (byte)buffer.read();
@@ -348,8 +348,8 @@
         return getSequence(
                 startLen,
                 false); // no need to retain original encoded form
-        // END Android-changed: Original encoded form needed for APKs parsing/validation
     }
+    // END Android-changed: Original encoded form needed for APKs parsing/validation.
 
     /**
      * Return a set of encoded entities.  ASN.1 sets are unordered,
@@ -381,7 +381,7 @@
      */
     public DerValue[] getSet(int startLen, boolean implicit)
         throws IOException {
-        // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation
+        // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation.
         return getSet(
             startLen,
             implicit,
@@ -398,7 +398,7 @@
             }
         }
         return (readVector(startLen, originalEncodedFormRetained));
-        // END Android-changed: Original encoded form needed for APKs parsing/validation
+        // END Android-changed: Original encoded form needed for APKs parsing/validation.
     }
 
     /*
@@ -407,7 +407,7 @@
      * this same helper routine.
      */
     protected DerValue[] readVector(int startLen) throws IOException {
-        // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation
+        // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation.
         return readVector(
             startLen,
             false); // no need to retain original encoded form
@@ -420,7 +420,7 @@
      */
     protected DerValue[] readVector(int startLen,
             boolean originalEncodedFormRetained) throws IOException {
-        // END Android-changed: Original encoded form needed for APKs parsing/validation
+        // END Android-changed: Original encoded form needed for APKs parsing/validation.
         DerInputStream  newstr;
 
         byte lenByte = (byte)buffer.read();
@@ -465,7 +465,7 @@
         DerValue value;
 
         do {
-            // Android-changed: Original encoded form needed for APKs parsing/validation
+            // Android-changed: Original encoded form needed for APKs parsing/validation.
             value = new DerValue(newstr.buffer, originalEncodedFormRetained);
             vec.addElement(value);
         } while (newstr.available() > 0);
diff --git a/ojluni/src/main/java/sun/security/util/DerValue.java b/ojluni/src/main/java/sun/security/util/DerValue.java
index 3045995..7828820 100644
--- a/ojluni/src/main/java/sun/security/util/DerValue.java
+++ b/ojluni/src/main/java/sun/security/util/DerValue.java
@@ -72,13 +72,13 @@
 
     private int                 length;
 
-    // BEGIN Android-added: Original encoded form needed for APKs parsing/validation
+    // BEGIN Android-added: Original encoded form needed for APKs parsing/validation.
     /**
      * The original encoded form of the whole value (tag, length, and value)
      * or null if the form was not provided or was not retained during parsing.
      */
     private byte[]              originalEncodedForm;
-    // END Android-added: Original encoded form needed for APKs parsing/validation
+    // END Android-added: Original encoded form needed for APKs parsing/validation.
 
     /*
      * The type starts at the first byte of the encoding, and
@@ -251,7 +251,7 @@
     /*
      * package private
      */
-    // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation
+    // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation.
     DerValue(DerInputBuffer in, boolean originalEncodedFormRetained)
             throws IOException {
         // XXX must also parse BER-encoded constructed
@@ -297,7 +297,7 @@
             int consumed = in.getPos() - startPosInInput;
             originalEncodedForm = in.getSlice(startPosInInput, consumed);
         }
-    // END Android-changed: Original encoded form needed for APKs parsing/validation
+    // END Android-changed: Original encoded form needed for APKs parsing/validation.
     }
 
     /**
@@ -838,7 +838,7 @@
         }
     }
 
-    // BEGIN Android-added: Original encoded form needed for APKs parsing/validation
+    // BEGIN Android-added: Original encoded form needed for APKs parsing/validation.
     /**
      * Returns the original encoded form or {@code null} if the form was not
      * retained or is not available.
@@ -847,7 +847,7 @@
         return (originalEncodedForm != null)
                 ? originalEncodedForm.clone() : null;
     }
-    // END Android-added: Original encoded form needed for APKs parsing/validation
+    // END Android-added: Original encoded form needed for APKs parsing/validation.
 
     /**
      * Returns a DER-encoded value, such that if it's passed to the
diff --git a/ojluni/src/main/java/sun/security/x509/X509CertImpl.java b/ojluni/src/main/java/sun/security/x509/X509CertImpl.java
index 57a8f71..f15b998 100644
--- a/ojluni/src/main/java/sun/security/x509/X509CertImpl.java
+++ b/ojluni/src/main/java/sun/security/x509/X509CertImpl.java
@@ -192,7 +192,7 @@
         }
     }
 
-    // BEGIN Android-removed: unused code
+    // BEGIN Android-removed: unused code.
     /*
     /**
      * unmarshals an X.509 certificate from an input stream.  If the
@@ -280,7 +280,7 @@
         return der;
     }
     */
-    // END Android-removed: unused code
+    // END Android-removed: unused code.
 
     /**
      * Construct an initialized X509 Certificate. The certificate is stored
@@ -310,7 +310,7 @@
         }
     }
 
-    // BEGIN Android-added: Ctor to retain original encoded form for APKs parsing
+    // BEGIN Android-added: Ctor to retain original encoded form for APKs parsing.
     /**
      * Unmarshal a certificate from its encoded form, parsing a DER value.
      * This form of constructor is used by agents which need to examine
@@ -328,7 +328,7 @@
             throw new CertificateException("Unable to initialize, " + e, e);
         }
     }
-    // END Android-added: Ctor to retain original encoded form for APKs parsing
+    // END Android-added: Ctor to retain original encoded form for APKs parsing.
 
     /**
      * Appends the certificate to an output stream.
@@ -1814,7 +1814,7 @@
             throw new CertificateParsingException(
                       "invalid DER-encoded certificate data");
 
-        // Android-changed: Needed for providing encoded form of cert
+        // Android-changed: Needed for providing encoded form of cert.
         // signedCert = val.toByteArray();
         signedCert =
                 (originalEncodedForm != null)
@@ -1972,12 +1972,12 @@
     private ConcurrentHashMap<String,String> fingerprints =
             new ConcurrentHashMap<>(2);
 
-// BEGIN Android-removed
+// BEGIN Android-removed: unused code.
 //    public String getFingerprint(String algorithm) {
 //        return fingerprints.computeIfAbsent(algorithm,
 //                x -> getFingerprint(x, this));
 //    }
-// END Android-removed
+// END Android-removed: unused code.
 
     /**
      * Gets the requested finger print of the certificate. The result
diff --git a/ojluni/src/main/java/sun/util/locale/LocaleMatcher.java b/ojluni/src/main/java/sun/util/locale/LocaleMatcher.java
index 70fabc7..37eb416 100644
--- a/ojluni/src/main/java/sun/util/locale/LocaleMatcher.java
+++ b/ojluni/src/main/java/sun/util/locale/LocaleMatcher.java
@@ -212,7 +212,7 @@
             if (range.equals("*")) {
                 continue;
             }
-            // Android-changed: backport OpenJDK 9 fix for JDK-8166994
+            // Android-changed: backport OpenJDK 9 fix for JDK-8166994.
             String rangeForRegex = range.replace("*", "\\p{Alnum}*");
             while (rangeForRegex.length() > 0) {
                 for (String tag : tags) {
@@ -242,7 +242,7 @@
     }
 
     public static List<LanguageRange> parse(String ranges) {
-        // Android-changed: backport OpenJDK 9 fix for JDK-8166994
+        // Android-changed: backport OpenJDK 9 fix for JDK-8166994.
         ranges = ranges.replace(" ", "").toLowerCase();
         if (ranges.startsWith("accept-language:")) {
             ranges = ranges.substring(16); // delete unnecessary prefix
@@ -332,7 +332,7 @@
         return list;
     }
 
-    // BEGIN Android-added: backport OpenJDK 9 fix for JDK-8166994
+    // BEGIN Android-added: backport OpenJDK 9 fix for JDK-8166994.
     /**
      * A faster alternative approach to String.replaceFirst(), if the given
      * string is a literal String, not a regex.
@@ -347,7 +347,7 @@
                     + range.substring(pos + substr.length());
         }
     }
-    // END Android-added: backport OpenJDK 9 fix for JDK-8166994
+    // END Android-added: backport OpenJDK 9 fix for JDK-8166994.
 
     private static String[] getEquivalentsForLanguage(String range) {
         String r = range;
@@ -357,7 +357,7 @@
                 String equiv = LocaleEquivalentMaps.singleEquivMap.get(r);
                 // Return immediately for performance if the first matching
                 // subtag is found.
-// BEGIN Android-added: backport OpenJDK 9 fix for JDK-8166994
+// BEGIN Android-added: backport OpenJDK 9 fix for JDK-8166994.
 // Upstream bug: https://bugs.openjdk.java.net/browse/JDK-8166994
 // Upstream fix: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/60837db5d445
                 return new String[]{replaceFirstSubStringMatch(range,
@@ -370,7 +370,7 @@
                             r, equivs[i]);
                 }
                 return result;
-// END Android-added: backport OpenJDK 9 fix for JDK-8166994
+// END Android-added: backport OpenJDK 9 fix for JDK-8166994.
             }
 
             // Truncate the last subtag simply.
diff --git a/tools/patch-style/libcore-patch-style.awk b/tools/patch-style/libcore-patch-style.awk
new file mode 100644
index 0000000..e138298
--- /dev/null
+++ b/tools/patch-style/libcore-patch-style.awk
@@ -0,0 +1,175 @@
+# Copyright 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.
+
+# Simple libcore patch-style checking based on http://go/libcore-patch-style.
+#
+# See sample-input.java for examples of matches and failures.
+#
+# Usage:
+#  awk -f libcore-patch-style.awk <file0> [... fileN]
+#
+# This script ignores any files whose name does not end in the suffix ".java".
+#
+# To scan all source code in the libcore tree:
+#  $ cd libcore
+#  $ find . -type f | xargs awk -f tools/patch-style/libcore-patch-style.awk
+#
+# To find sources with the most issues:
+#  $ cd libcore
+#  $ find . -type f | xargs awk -f tools/patch-style/libcore-patch-style.awk \
+#                   | grep -F ./ | sed -e 's/:.*//' | uniq -c | sort -n -r | head
+
+BEGIN {
+  g_errors = 0                    # Number of errors accumulated.
+  g_expected_end = ""             # Expected END line.
+  g_max_length = 100              # Maximum line length for markers (0 == no checking).
+  g_stop_oneline_interleaving = 0 # Error one-line comments between BEGIN and END markers.
+}
+
+BEGINFILE {
+  # Skip files whose names do not have a .java suffix.
+  if (FILENAME !~ /\.java$/) {
+    nextfile
+  }
+
+  # Reset the line number for reporting errors back to zero.
+  NR = 0
+
+  # Clear expected end marker as processing a new file.
+  g_expected_end = ""
+}
+
+function error(message) {
+  print(FILENAME ":" NR ":", message "\n")
+  g_errors += 1;
+}
+
+function expectationError(reason, expected, actual) {
+  error(reason "\n  Expected: \"" expected "\"\n  Actual:   \"" actual "\"")
+}
+
+function inputError(reason, actual) {
+  error(reason "\n  Input:    \"" actual "\"")
+}
+
+function checkLineLength(line) {
+  if (g_max_length > 0 && length(line) > g_max_length) {
+    inputError("Line too long", line)
+  }
+}
+
+function leftTrim(message) {
+  return gensub(/^ */, "", 1, message)
+}
+
+function failIfEndExpected() {
+  if (g_expected_end != "") {
+    expectationError("Missing END marker.", g_expected_end, $0)
+    g_expected_end = ""
+  }
+}
+
+function expectEndFor(begin_line) {
+  g_expected_end = begin_line
+  sub("BEGIN", "END", g_expected_end)
+}
+
+function actualEndFor(actual_line) {
+  if (actual_line != g_expected_end) {
+    expectationError("Bad END marker.", g_expected_end, actual_line)
+  }
+  g_expected_end = ""
+}
+
+function processBeginMarker(line) {
+  failIfEndExpected()
+  expectEndFor(line)
+}
+
+function processEndMarker(line) {
+  actualEndFor(line)
+}
+
+# BEGIN marker ending in a period.
+/^ *\/\/ BEGIN Android-(added|changed|note|removed):.*\./ {
+  checkLineLength($0)
+  processBeginMarker($0)
+  next
+}
+
+# BEGIN marker ending in a period.
+/^ *\/\/ END Android-(added|changed|note|removed):.*\./ {
+  checkLineLength($0)
+  processEndMarker($0)
+  next
+}
+
+# BEGIN marker ending in a bug reference.
+/^ *\/\/ BEGIN Android-(added|changed|note|removed):.*[.](http:\/\/)?b\/[1-9][0-9]*/ {
+  checkLineLength($0)
+  processBeginMarker($0)
+  next
+}
+
+# BEGIN marker ending in anything else, oops!
+/^ *\/\/ BEGIN Android-(added|changed|note|removed)[^:].*/ {
+  inputError("BEGIN marker is missing colon or description.", $0)
+  next
+}
+
+# END marker, should be paired with last BEGIN marker.
+/^ *\/\/ END Android-(added|changed|note|removed):.*/ {
+  checkLineLength($0)
+  processEndMarker($0)
+  next
+}
+
+# One line change marker ending in a period.
+/^ *\/\/ Android-(added|changed|note|removed):.*[.]/ {
+  checkLineLength($0)
+  if (g_stop_oneline_interleaving) {
+    failIfEndExpected()
+  }
+  next
+}
+
+# One line change marker ending in a bug reference.
+/^ *\/\/ Android-(added|changed|note|removed):[.](http:\/\/)?b\/[1-9][0-9]*/ {
+  checkLineLength($0)
+  if (g_stop_oneline_interleaving) {
+    failIfEndExpected()
+  }
+  next
+}
+
+# One line change marker missing comment after colon.
+/^ *\/\/ BEGIN Android-(added|changed|note|removed).*/ {
+  inputError("Bad change marker: missing colon or description.", $0)
+  next
+}
+
+# Something that looks like a potential change marker.
+/^ *(\/\*|\/\/|\*) *(Android|ANDROID)-/ {
+  if (g_stop_oneline_interleaving) {
+    failIfEndExpected()
+  }
+  inputError("Bad change marker.", $0)
+  next
+}
+
+END {
+  failIfEndExpected()
+  printf("Found " g_errors " libcore patch style issues.\n")
+  exit g_errors == 0
+}
diff --git a/tools/patch-style/sample-input.java b/tools/patch-style/sample-input.java
new file mode 100644
index 0000000..8d55cfe
--- /dev/null
+++ b/tools/patch-style/sample-input.java
@@ -0,0 +1,32 @@
+# HAPPY PATHS
+    // BEGIN Android-added: something bot like.
+    // END Android-added: something bot like.
+
+    // BEGIN Android-changed: something bot like. http://b/12345
+    // END Android-changed: something bot like. http://b/12345
+
+    // BEGIN Android-removed: coffee stain. b/12345
+    // END Android-changed: something bot like. http://b/12345
+
+    // Android-added: hello world.
+    // Android-change: hello world. http://b/1100
+    // Android-remove: goodbye world. http://b/999912
+
+# UNHAPPY PATHS
+
+    //  BEGIN Android-added something bot like.
+    //  END Android-added something bot like.
+
+    // Android-note: blah
+    // Android-note: blah.
+    // Android-changed hello
+    // Android-added: hello
+
+    /* Android-note blah balh */
+    /* Android note: blah balh */
+    /* ANDROID android android android */
+    * ANDROID *
+
+Android-bar
+
+// BEGIN Android-removed: END from last line.
diff --git a/tools/testmapping/README b/tools/testmapping/README
new file mode 100644
index 0000000..0222018
--- /dev/null
+++ b/tools/testmapping/README
@@ -0,0 +1,36 @@
+These scripts help generate the libcore TEST_MAPPING smoke tests, i.e. a set of
+tests to run on every change, chosen to run as many as possible in less than
+some time limit.
+
+The process is as follows.
+1. Do `source build/envsetup.sh` and `lunch <whatever>` as normal.
+2. Run the CtsLibcoreTestCases tests to generate logs to extract timings from.
+   This can be done with `atest CtsLibcoreTestCases` as normal. Make sure to use
+   an appropriate device (virtual or physical).
+3. Do that two more times. We'll use best-of-three timings, since sometimes a
+   test takes an unusual amount of time (perhaps because of GC pause or other
+   jank) and it should not be excluded for that.
+4. Run the save_logs.py script to copy the logs from out/ to libcore/smoketest.
+   (Empty that directory if it exists already). This is interactive and allows
+   you to pick the runs you want. (If you prefer, you can run this after each
+   run, rather than once after all three runs.)
+5. Run the gen_smoke_tests.py script to generate libcore/TEST_MAPPING.
+6. Check stdout from the script looks okay (not too many warnings, sensible
+   numbers, etc.).
+7. Check the generated TEST_MAPPING looks okay.
+8. Do e.g. `time atest --test-mapping libcore` to check it runs okay.
+9. Delete libcore/smoketest/ once you're happy.
+10. Submit the new TEST_MAPPING.
+
+The scripts take no options. There are some constants at the start you can
+adjust. (These could be converted to command-line options if convenient.)
+
+See comments in the scripts for more on how they work.
+
+At time of writing, with the current configuration, this generates a sensible
+number of classes to exclude, so the TEST_MAPPING looks reasonable. If this list
+becomes too long, we'll have to find a way to simplify it, by rolling up to a
+higher granularity. Given the way that atest et al are configured, that will
+probably mean excluding more things.
+
+TODO(peteg): What about PTS?
diff --git a/tools/testmapping/gen_smoke_tests.py b/tools/testmapping/gen_smoke_tests.py
new file mode 100755
index 0000000..159be1b
--- /dev/null
+++ b/tools/testmapping/gen_smoke_tests.py
@@ -0,0 +1,474 @@
+#!/usr/bin/env python2
+#
+#   Copyright 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.
+
+"""Tool to generate data for smoke tests."""
+
+from __future__ import print_function
+
+import collections
+import datetime
+import gzip
+import operator
+import os
+import re
+import tempfile
+
+import jinja2
+import util
+
+ANDROID_REPOSITORY_ROOT = util.android_repository_root()
+LIBCORE_DIR = os.path.join(ANDROID_REPOSITORY_ROOT, 'libcore')
+LOGS_DIR = os.path.join(LIBCORE_DIR, 'smoketest')
+REQUIRED_RUNS = 3
+CTS_LOG_LINE_PATTERN = (r'(\d+)-(\d+) +(\d+):(\d+):(\d+)\.(\d+) +\d+ +\d+ +'
+                        r'[^ ]+ (CtsTestRunListener|TestRunner) *: *(.+)')
+THIS_YEAR = datetime.datetime.now().year
+START_MATCHER = ('CtsTestRunListener', r'Now executing\s*:\s*(.+)')
+TESTS_RAN_MATCHER = ('TestRunner', r'started\s*:.*')
+END_MATCHER = ('CtsTestRunListener', r'Total memory\s*:.+')
+HARD_END_MATCHER = ('TestRunner', r'run finished\s*:.+')
+JAVA_CLASS_PATTERN = r'(?:([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)\.)?[a-zA-Z_][a-zA-Z0-9_]*'
+MAX_RUN_TIME = datetime.timedelta(minutes=10)
+OUT_DIR = tempfile.mkdtemp()
+ROLL_UP_TEST_CLASSES_TO_PACKAGE = False
+CTS_MODULE_NAME = 'CtsLibcoreTestCases'
+
+TEST_MAPPING_TEMPLATE = jinja2.Template("""
+{
+  "presubmit": [
+    {
+      "name": "{{module}}",
+      "options": [{% for test in exclusions %}
+        {
+          "exclude-filter": "{{test}}"
+        }{% if not loop.last %},{% endif %}{% endfor %}
+      ]
+    }
+  ]
+}
+""".strip())
+
+
+def find_all_log_files():
+  """Returns a list of the log files to read."""
+  if not os.path.isdir(LOGS_DIR):
+    raise Exception('Could not find logs directory ' + LOGS_DIR)
+  filenames = os.listdir(LOGS_DIR)
+  if not filenames:
+    raise Exception('Found empty logs directory ' + LOGS_DIR)
+  if len(filenames) != REQUIRED_RUNS:
+    raise Exception('Expected to find exactly %d files in %s, found %d' %
+                    (REQUIRED_RUNS, LOGS_DIR, len(filenames)))
+  return map(lambda f: os.path.join(LOGS_DIR, f), filenames)
+
+
+def read_cts_logs(filename):
+  """Read CTS entries from a log file.
+
+  Args:
+    filename: The name of the file to read.
+
+  Yields:
+    Tuples of timestamps (as datetimes), log sources, and log messages.
+  """
+  print('Reading ' + util.printable_path(filename))
+  with gzip.open(filename, mode='rt') as log_file:
+    for line in log_file:
+      cts_match = re.match(CTS_LOG_LINE_PATTERN, line)
+      if cts_match:
+        assert len(cts_match.groups()) == 8
+        timestamp = datetime.datetime(
+            year=THIS_YEAR,
+            month=int(cts_match.group(1)),
+            day=int(cts_match.group(2)),
+            hour=int(cts_match.group(3)),
+            minute=int(cts_match.group(4)),
+            second=int(cts_match.group(5)),
+            microsecond=1000 * int(cts_match.group(6)))
+        source = cts_match.group(7)
+        message = cts_match.group(8)
+        yield (timestamp, source, message)
+
+
+def match(matcher, got_source, message):
+  """Check whether a log line matches requirements.
+
+  Args:
+    matcher: A pair of the required log source and a pattern to match messages.
+    got_source: The actual log source.
+    message: The actual message.
+
+  Returns:
+    A MatchObject from the pattern match against the message, or None.
+  """
+  (want_source, pattern) = matcher
+  if got_source == want_source:
+    return re.match(pattern, message)
+  else:
+    return None
+
+
+def parse_running_times(filename):
+  """Parse the running times from a log file.
+
+  Args:
+    filename: The name of the file to read.
+
+  Yields:
+    Pairs of test names and running times (as timedeltas). Also emits the
+    overall elapsed time from the start of the first test to the end of the last
+    test with the key 'OVERALL'.
+
+  Raises:
+    Exception: The log file entries didn't look like we expected.
+  """
+  executing = None
+  start_timestamp = None
+  ran_tests = False
+  overall_start_timestamp = None
+  overall_end_timestamp = None
+  for (timestamp, source, message) in read_cts_logs(filename):
+    start_match = match(START_MATCHER, source, message)
+    tests_ran_match = match(TESTS_RAN_MATCHER, source, message)
+    end_match = match(END_MATCHER, source, message)
+    hard_end_match = match(HARD_END_MATCHER, source, message)
+    if not executing:
+      if start_match:
+        assert len(start_match.groups()) == 1
+        executing = start_match.group(1)
+        start_timestamp = timestamp
+        if not overall_start_timestamp:
+          overall_start_timestamp = timestamp
+    else:
+      if start_match:
+        raise Exception(
+            'Found start for %s while waiting for end for %s at %s in %s' %
+            (start_match.group(1), executing, str(timestamp), filename))
+      if tests_ran_match:
+        ran_tests = True
+      if end_match or hard_end_match:
+        running_time = timestamp - start_timestamp
+        # We see two types of execution in the logs. One appears to be some kind
+        # of dry run which doesn't actually run any tests (and completes
+        # significantly faster). We want the one that actually runs tests.
+        if ran_tests:
+          yield (executing, running_time)
+        executing = None
+        start_timestamp = None
+        ran_tests = False
+        overall_end_timestamp = timestamp
+  if executing:
+    raise Exception('Reached EOF while waiting for end for %s in %s' %
+                    (executing, filename))
+  yield ('OVERALL', overall_end_timestamp - overall_start_timestamp)
+
+
+def collect_running_times(filenames):
+  """Collect running times from some log file.
+
+  Args:
+    filenames: The names of the files to read.
+
+  Returns:
+    A tuple containing (1) a dictionary mapping test names to sets of running
+    times (as timedeltas), and (2) a list of overall running times (i.e. elapsed
+    times from the start of the first test to the end of the last test).
+  """
+  times_by_test = collections.defaultdict(list)
+  output_path = os.path.join(OUT_DIR, 'test_times.txt')
+  overall_times = []
+  with open(output_path, 'w') as output:
+    for filename in filenames:
+      for (test_name, time) in parse_running_times(filename):
+        output.write('%s: %g ms\n' % (test_name, time.total_seconds() * 1000))
+        if test_name == 'OVERALL':
+          overall_times.append(time)
+        else:
+          times_by_test[test_name].append(time)
+  print('Wrote test times to ' + util.printable_path(output_path))
+  return (times_by_test, overall_times)
+
+
+def process_running_times(times_by_test):
+  """Processes the collected running times.
+
+  Args:
+    times_by_test: A dictionary mapping test names to sets of running times.
+
+  Returns:
+    A dictionary mapping test names to fastest running times.
+  """
+  for (test, times) in times_by_test.iteritems():
+    if len(times) != REQUIRED_RUNS:
+      print('Warning: Only found %d runs for %s' % (len(times), test))
+  return {test: min(times) for (test, times) in times_by_test.iteritems()}
+
+
+def calculate_overhead_ratio(overall_times, fastest_time_by_test):
+  """Calculates a ratio for the actual overall time to the sum of test times.
+
+   The actual overall times are the elapsed times from the start of the first
+   test to the end of the last test. The average of these is used. The ratio is
+   taken with the sume of the fastest time for each test (which is what will be
+   used for scoring).
+
+  Args:
+    overall_times: A list of overall running times.
+    fastest_time_by_test: A dictionary mapping test names to fastest running
+      times.
+
+  Returns:
+    The ratio.
+  """
+  average_overall_time = sum(overall_times,
+                             datetime.timedelta(0)) / len(overall_times)
+  total_time_by_test = sum(fastest_time_by_test.values(), datetime.timedelta(0))
+  ratio = (
+      average_overall_time.total_seconds() / total_time_by_test.total_seconds())
+  print(
+      'Average time for run is %g seconds, sum of fastest test times is %g, ratio is %g'
+      % (average_overall_time.total_seconds(),
+         total_time_by_test.total_seconds(), ratio))
+................................................................................
+  # N.B. Possible future enhancement: Currently, because# we take the fastest of
+  # three runs, a real run will always be slightly slower than we predict. We
+  # could multiply in another overhead factor to account for this, e.g. by
+  # looking at the ratio of the mean of the three to the fastest of the three.
+  # (This factor should be applied globally rather than individually to each
+  # test so as not to penalize tests which happened to have a slow run or two.)
+  # This is not a high priority since for now we can just set MAX_RUN_TIME a bit
+  # low to allow for this.
+  return ratio
+
+
+def get_parent(name):
+  """Returns the parent of a Java class or package name."""
+  class_match = re.match(JAVA_CLASS_PATTERN, name)
+  if not class_match:
+    raise Exception('Could not parse Java class name ' + name)
+  assert len(class_match.groups()) == 1
+  return class_match.group(1)
+
+
+def group_times_by_package(times_by_test):
+  """Groups the test classes by package name, summing the times.
+
+  Args:
+    times_by_test: A dictionary mapping test names to fastest running times.
+
+  Returns:
+    A dictionary mapping package names to total fastest running times.
+  """
+  time_by_package = collections.defaultdict(datetime.timedelta)
+  for (clazz, time) in times_by_test.iteritems():
+    package = get_parent(clazz)
+    if package:  # A few tests have no package. They're weird, let's skip them.
+      time_by_package[package] = time_by_package[package] + time
+  output_path = os.path.join(OUT_DIR, 'package_times.txt')
+  with open(output_path, 'w') as output:
+    for (package, time) in time_by_package.iteritems():
+      output.write('%s: %s ms\n' % (package, time.total_seconds() * 1000.0))
+  print('Wrote package times to ' + util.printable_path(output_path))
+  return time_by_package
+
+
+def find_tests_to_run(time_by_test, overhead_ratio):
+  """Finds the tests to actually run.
+
+  The tests chosen will be the fastest set such that their total time, when
+  multiplied by the overhead ratio, is less than the maximum.
+
+  Args:
+    time_by_test: A dictionary mapping test names to total fastest running
+      times. The names can be packages, classes, or a mixture of the two.
+    overhead_ratio: A ratio for the actual overall time to the sum of test
+      times.
+
+  Returns:
+    A list of test names whose running times are below the threshold.
+
+  Raises:
+    Exception: The total running time of all the tests is below the threhold.
+  """
+  test_inclusions = {test: False for test in time_by_test.keys()}
+  included = 0
+  total_time = datetime.timedelta()
+  output_path = os.path.join(OUT_DIR, 'included_tests.txt')
+  adjusted_max_run_time_seconds = MAX_RUN_TIME.total_seconds() / overhead_ratio
+  with open(output_path, 'w') as output:
+    for (test, time) in sorted(
+        time_by_test.iteritems(), key=operator.itemgetter(1)):
+      if (total_time + time).total_seconds() <= adjusted_max_run_time_seconds:
+        test_inclusions[test] = True
+        included += 1
+        total_time += time
+        output.write('%s: %g ms -> %g ms\n' %
+                     (test, time.total_seconds() * 1000.0,
+                      total_time.total_seconds() * 1000.0))
+      else:
+        print('Can run fastest %d of %d tests in %g * %g = %g seconds' %
+              (included, len(time_by_test), total_time.total_seconds(),
+               overhead_ratio, total_time.total_seconds() * overhead_ratio))
+        print('Wrote tests to include to ' + util.printable_path(output_path))
+        return test_inclusions
+  raise Exception('Apparently we can run all the tests? This smells wrong.')
+
+
+def build_test_tree(tests):
+  """Builds a tree of tests.
+
+  Args:
+    tests: The list of tests to build into a tree. These can be packages,
+      classes, or a mixture of the two.
+
+  Returns:
+    A dictionary mapping every test's ancestors to its children. The roots
+    appear as children of None.
+  """
+  tree = collections.defaultdict(set)
+  for test in tests:
+    while True:
+      parent = get_parent(test)
+      tree[parent].add(test)
+      if parent:
+        test = parent
+      else:
+        break
+  return tree
+
+
+def build_exclusion_list(test_inclusions):
+  """Builds a list of tests to exclude.
+
+  Args:
+    test_inclusions: A dictionary mapping test names to whether or not they
+      should be included in the smoke tests. The names can be packages, classes,
+      or a mixture of the two.
+
+  Returns:
+    A list of the exclusions. These could be individual tests, or packages or
+    some part of the package hierarchy if they are to be entirely excluded.
+  """
+  tree = build_test_tree(test_inclusions.keys())
+  exclusions = []
+
+  # We do a DFS of the tree, rolling up exclusions as far as possible, i.e. if
+  # an entire branch is excluded, we exclude that branch rather than all of its
+  # leaves.
+
+  def visit(test):
+    """Visitor for a DFS of the tree.
+
+    Args:
+      test: The test to visit (either a class or package name).
+
+    Returns:
+      Whether or not the parent should include this node in the tree.
+
+    Raises:
+      Exception: The tree had an unexpected structure.
+    """
+    if test in test_inclusions:
+      # We only expect to have inclusion status for the leaves of the tree.
+      # Check that this is the case.
+      if test in tree:
+        raise Exception('The name %s is used for a leaf and a branch!' % test)
+      # Return to the parent node whether this leaf is included.
+      return test_inclusions[test]
+    else:
+      # We expect to have inclusion status for all leaves of the tree. Check
+      # that this is the case.
+      if test not in tree:
+        raise Exception('Leaf %s has no inclusion status!' % test)
+      # Look at all the children of this node.
+      any_child_included = False
+      child_exclusions = []
+      for child in tree[test]:
+        child_included = visit(child)
+        if child_included:
+          any_child_included = True
+        else:
+          child_exclusions.append(child)
+      # If any children are included, we will count this node as included, so we
+      # have to add any excluded children to the exclusion list.
+      if any_child_included:
+        for child in child_exclusions:
+          exclusions.append(child)
+      # Now return whether this node should be counted as included, which means
+      # whether any children are included.
+      return any_child_included
+
+  # Start the DFS at each root of the tree.
+  for root in tree[None]:
+    root_included = visit(root)
+    # If any of the roots are counted as excluded, add them to the list.
+    if not root_included:
+      exclusions.append(root)
+
+  # Finally, sort and return the list of exclusions.
+  return sorted(exclusions)
+
+
+def self_test():
+  """Self-test for the build_include_exclude_list logic."""
+  test_inclusions = {
+      'a.x': True,
+      'a.y': True,
+      'b.x': True,
+      'b.y': False,
+      'c.x': False,
+      'c.y': False,
+      'd.x.m': True,
+      'd.x.n': True,
+      'd.y.m': True,
+      'd.y.n': False,
+      'd.z.m': False,
+      'd.z.n': False,
+  }
+  expected_exclusions = [
+      'b.y',
+      'c',
+      'd.y.n',
+      'd.z',
+  ]
+  actual_exclusions = build_exclusion_list(test_inclusions)
+  if actual_exclusions != expected_exclusions:
+    raise Exception('Self test failed! Expected %s but got %s' %
+                    (expected_exclusions, actual_exclusions))
+
+
+def main():
+  """The main method."""
+  self_test()
+  filenames = find_all_log_files()
+  (times_by_test, overall_times) = collect_running_times(filenames)
+  fastest_time_by_test = process_running_times(times_by_test)
+  overhead_ratio = calculate_overhead_ratio(overall_times, fastest_time_by_test)
+  if ROLL_UP_TEST_CLASSES_TO_PACKAGE:
+    time_by_package = group_times_by_package(fastest_time_by_test)
+    test_inclusions = find_tests_to_run(time_by_package, overhead_ratio)
+  else:
+    test_inclusions = find_tests_to_run(fastest_time_by_test, overhead_ratio)
+  exclusions = build_exclusion_list(test_inclusions)
+  output_path = os.path.join(LIBCORE_DIR, 'TEST_MAPPING')
+  with open(output_path, 'w') as output:
+    output.write(
+        TEST_MAPPING_TEMPLATE.render(
+            module=CTS_MODULE_NAME, exclusions=exclusions))
+  print('Wrote test mapping to ' + util.printable_path(output_path))
+
+
+main()
diff --git a/tools/testmapping/save_logs.py b/tools/testmapping/save_logs.py
new file mode 100755
index 0000000..8f737b3e
--- /dev/null
+++ b/tools/testmapping/save_logs.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python2
+#
+#   Copyright 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.
+
+"""Tool to save logs files for use by gen_smoke_tests.py."""
+
+from __future__ import print_function
+
+import glob
+import os
+import shutil
+import sys
+
+import util
+
+ANDROID_REPOSITORY_ROOT = util.android_repository_root()
+LOGS_ROOT = os.path.join(ANDROID_REPOSITORY_ROOT, 'out', 'host', 'linux-x86',
+                         'cts', 'android-cts', 'logs')
+CTS_LOGS_PATTERN = os.path.join(LOGS_ROOT, '*', '*',
+                                'device_logcat_test_*.txt.gz')
+LIBCORE_DIR = os.path.join(ANDROID_REPOSITORY_ROOT, 'libcore')
+DESTINATION_DIR = os.path.join(LIBCORE_DIR, 'smoketest')
+
+
+def check_destination():
+  """Ensures the destination directory to copy the files to exists."""
+  if not os.path.isdir(LIBCORE_DIR):
+    raise Exception('Could not find directory ' + LIBCORE_DIR)
+  if not os.path.isdir(DESTINATION_DIR):
+    print('Making destination directory ' +
+          util.printable_path(DESTINATION_DIR))
+    os.mkdir(DESTINATION_DIR, 0o755)
+  else:
+    print('Found destination directory ' + util.printable_path(DESTINATION_DIR))
+
+
+def is_real_log_file(filename):
+  """Returns whether the filename is one we should use or not."""
+  return 'latest' not in filename
+
+
+def find_all_log_files():
+  """Finds all CTS log files in the expected directory.
+
+  Returns:
+    A list of filenames, sorted by mtime, most recent first.
+  Raises:
+    Exception: Not enough log files found.
+  """
+  print('Looking for logs in %s' % util.printable_path(LOGS_ROOT))
+  print('+++ ' + CTS_LOGS_PATTERN)
+  for f in glob.glob(CTS_LOGS_PATTERN):
+    print('*** ' + f)
+  sources = [f for f in glob.glob(CTS_LOGS_PATTERN) if is_real_log_file(f)]
+  if not sources:
+    raise Exception('Found no logs files!')
+  return sorted(sources, key=os.path.getmtime, reverse=True)
+
+
+def relative_source_name(source):
+  """Returns the name of a source file, relative to the logs root."""
+  return os.path.relpath(source, LOGS_ROOT)
+
+
+def flatten_name(name):
+  """Returns a flattened version of a path, using _ to separate."""
+  parts = []
+  while name:
+    (head, tail) = os.path.split(name)
+    parts.insert(0, tail)
+    name = head
+  return '_'.join(parts)
+
+
+def destination_path(name):
+  """Returns the destination path for a given name (which must be flattened)."""
+  assert not os.path.dirname(name)
+  return os.path.join(DESTINATION_DIR, name)
+
+
+def get_indexes_from_user(prompt, options):
+  """Gets a sequence of indexes between 1 and max from the user.
+
+  Args:
+    prompt: A prompt to show to the user.
+    options: The options to show to the user.
+
+  Yields:
+    The indexes.
+  """
+  for (index, option) in enumerate(options):
+    print('%d: %s' % (index + 1, option))
+  while True:
+    print(prompt)
+    instr = sys.stdin.readline().strip()
+    if instr.lower() == 'q':
+      break
+    try:
+      index = int(instr)
+    except ValueError:
+      print('Not a valid index! Please try again')
+      continue
+    if index < 1 or index > len(options):
+      print('Not a valid index! Please try again')
+      continue
+    yield index - 1
+
+
+def do_copy(source):
+  """Copies the given source into the destination directory."""
+  destination = destination_path(flatten_name(relative_source_name(source)))
+  if os.path.exists(destination):
+    print('File already exists: ' + util.printable_path(destination))
+  else:
+    print('Copying %s to %s' %
+          (util.printable_path(source), util.printable_path(destination)))
+    shutil.copyfile(source, destination)
+
+
+def main():
+  check_destination()
+  sources = find_all_log_files()
+  for index in get_indexes_from_user(
+      'Enter the number of the file to save, or Q to quit',
+      map(relative_source_name, sources)):
+    do_copy(sources[index])
+  print('Bye!')
+
+
+main()
diff --git a/tools/testmapping/util.py b/tools/testmapping/util.py
new file mode 100644
index 0000000..b1cf937
--- /dev/null
+++ b/tools/testmapping/util.py
@@ -0,0 +1,34 @@
+#
+#   Copyright 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.
+
+"""Common functions shared between the scripts."""
+
+import os
+
+
+def android_repository_root():
+  """Returns the root of the tree."""
+  if 'ANDROID_BUILD_TOP' not in os.environ:
+    raise Exception('Environment variable ANDROID_BUILD_TOP not set')
+  return os.environ['ANDROID_BUILD_TOP']
+
+
+def printable_path(filename):
+  """Returns the filename relative to the current dir, if it's under it."""
+  relative_path = os.path.relpath(filename)
+  if not relative_path.startswith('../'):
+    return relative_path
+  else:
+    return filename