Merge changes from topic "am-eb46eb48-7a23-41b3-8b69-98a255b23038" into oc-dev
am: db52df1433

Change-Id: If0c7001adcd8ecb3993e51ababc203ae0a6cdfcb
diff --git a/AndroidTest.xml b/AndroidTest.xml
new file mode 100644
index 0000000..78ed943
--- /dev/null
+++ b/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for libjavacore-benchmarks">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="libjavacore-benchmarks->/data/benchmarktest/libjavacore-benchmarks" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" >
+        <option name="native-benchmark-device-path" value="/data/benchmarktest" />
+        <option name="benchmark-module-name" value="libjavacore-benchmarks" />
+    </test>
+</configuration>
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 5a763da..3466db5 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -101,10 +101,7 @@
 LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs)
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVACFLAGS := $(local_javac_flags)
-# TODO(oth): Remove --min-sdk-version=26 when the O SDK version is determined.
-# For now it represents the minimum sdk version required for invoke-polymorphic.
-# This is only needed when ANDROID_COMPILE_WITH_JACK=false (b/36118520).
-LOCAL_DX_FLAGS := --core-library --min-sdk-version=26
+LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
 LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-oj
diff --git a/NativeCode.mk b/NativeCode.mk
index d8e9d64..9bfb88d 100644
--- a/NativeCode.mk
+++ b/NativeCode.mk
@@ -204,6 +204,7 @@
 LOCAL_C_INCLUDES += libcore/include
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE := libjavacore-benchmarks
+LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
 LOCAL_SHARED_LIBRARIES := libnativehelper
 LOCAL_CXX_STL := libc++
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..72d7fb4
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+nfuller@google.com
+pszczepaniak@google.com
+android-libcore-team+review@google.com
diff --git a/dalvik/src/main/java/dalvik/system/DexClassLoader.java b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
index 00252a1..db6fb1e 100644
--- a/dalvik/src/main/java/dalvik/system/DexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
@@ -16,8 +16,6 @@
 
 package dalvik.system;
 
-import java.io.File;
-
 /**
  * A class loader that loads classes from {@code .jar} and {@code .apk} files
  * containing a {@code classes.dex} entry. This can be used to execute code not
@@ -45,8 +43,7 @@
      * @param dexPath the list of jar/apk files containing classes and
      *     resources, delimited by {@code File.pathSeparator}, which
      *     defaults to {@code ":"} on Android
-     * @param optimizedDirectory directory where optimized dex files
-     *     should be written; must not be {@code null}
+     * @param optimizedDirectory this parameter is deprecated and has no effect
      * @param librarySearchPath the list of directories containing native
      *     libraries, delimited by {@code File.pathSeparator}; may be
      *     {@code null}
@@ -54,6 +51,6 @@
      */
     public DexClassLoader(String dexPath, String optimizedDirectory,
             String librarySearchPath, ClassLoader parent) {
-        super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
+        super(dexPath, null, librarySearchPath, parent);
     }
 }
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
deleted file mode 100644
index cd24094..0000000
--- a/expectations/brokentests.txt
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * This file contains expectations for tests that we'd like to eventually fix, but aren't urgent.
- */
-[
-{
-  description: "libcore.java.io.OldFileTest#test_deleteOnExit fails on IRM05 mysid-user",
-  name: "libcore.java.io.OldFileTest#test_deleteOnExit",
-  bug: 5834665
-},
-{
-  description: "We're retiring the security manager. Unfortunately, tests all over the place
-                need to check that they're secure, so they all fail when we refuse to install
-                a security manager. This suppresses all of these failures.",
-  result: EXEC_FAILED,
-  failure: "disable securityManager",
-  pattern: ".*java.lang.SecurityException\\s+at java.lang.System.setSecurityManager.*",
-  bug: 2585285
-},
-{
-  description: "ignore compilation errors due to different available APIs",
-  result: COMPILE_FAILED,
-  failure: "ignore compilation errors",
-  pattern: ".*\\.java:\\d+: cannot find symbol.*"
-},
-{
-  description: "the average length of possible UTF-8 sequences is 2 bytes.",
-  result: EXEC_FAILED,
-  name: "org.apache.harmony.tests.java.nio.charset.UTFCharsetEncoderTest#testSpecificDefaultValue",
-  substring: "junit.framework.AssertionFailedError: expected:<1.1> but was:<2.0>"
-},
-{
-  description: "Some tests (ExcludedProxyTest) connect to a public webserver to check that the HTTP client works",
-  result: EXEC_FAILED,
-  failure: "connect to the Internet",
-  pattern: ".*java.net.UnknownHostException:.*jcltest.apache.org.*"
-},
-{
-  description: "Some tests (ExcludedProxyTest) connect to a public webserver to check that the HTTP client works",
-  result: EXEC_FAILED,
-  names: [
-    "com.android.org.apache.harmony.luni.tests.java.net.ExcludedProxyTest"
-  ]
-},
-{
-  description: "Some tests depend on ICU data, which has changed. Others make assumptions about floating point rounding",
-  result: EXEC_FAILED,
-  names: [
-    "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_DateTimeConversion",
-    "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_GeneralConversionOther",
-    "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_LineSeparator",
-    "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_Percent"
-  ]
-},
-{
-  description: "(Needs investigation) Some tests make assertions that don't make sense, others use broken port allocation logic.",
-  result: EXEC_FAILED,
-  names: [
-    "org.apache.harmony.tests.java.net.InetAddressTest#test_isReachableLjava_net_NetworkInterfaceII_loopbackInterface"
-  ]
-},
-{
-  description: "Potentially flakey because they rely on a specific local TCP port being free.",
-  result: EXEC_FAILED,
-  names: [
-      "org.apache.harmony.tests.java.nio.channels.ServerSocketChannelTest#test_bind_explicitPort"
-  ]
-},
-{
-  description: "The ResourceBundle code under test is probably not used much on Android and needs a lot of attention.",
-  modes: [device],
-  bug: 13747957,
-  names: [
-      "org.apache.harmony.tests.java.util.ControlTest#test_needsReload_LStringLLocaleLStringLClassLoaderResourceBundleJ"
-  ]
-},
-{
-  description: "Fails in CTS, passes in CoreTestRunner.",
-  result: EXEC_FAILED,
-  modes: [device],
-  names: [
-      "org.apache.harmony.tests.java.net.URLConnection#test_getContentEncoding",
-      "libcore.java.text.OldNumberFormatTest#test_parseLjava_lang_String",
-      "libcore.java.nio.channels.OldSocketChannelTest#test_writeLjava_nio_ByteBuffer_Nonblocking_HugeData",
-      "org.apache.harmony.tests.java.lang.ProcessManagerTest#testSleep",
-      "libcore.java.security.cert.OldPKIXParametersTest#testPKIXParametersKeyStore04"
-  ]
-},
-{
-  description: "Suffers from DH slowness, disabling for now.",
-  result: EXEC_FAILED,
-  names: [
-      "libcore.java.security.OldDHTest#testDHGen",
-      "libcore.java.security.OldKeyPairGeneratorTestDH#testKeyPairGenerator",
-      "libcore.javax.crypto.spec.KeyPairGeneratorTestDH#testKeyPairGenerator",
-      "libcore.javax.crypto.spec.AlgorithmParametersTestDH#testAlgorithmParameters",
-      "libcore.javax.crypto.spec.AlgorithmParameterGeneratorTestDH#testAlgorithmParameterGenerator"
-  ]
-},
-{
-  description: "Destroys MD5 provider, hurts succeeding tests",
-  result: EXEC_FAILED,
-  names: [
-      "org.apache.harmony.tests.api.javax.security.cert.X509CertificateTest#testVerifyPublicKey",
-      "org.apache.harmony.tests.api.javax.security.cert.X509CertificateTest#testVerifyPublicKeyString"
-  ]
-},
-{
-  description: "Support_TestWebServer requires isolation.",
-  result: EXEC_FAILED,
-  names: [
-      "libcore.java.net.OldURLClassLoaderTest#test_findResourceLjava_lang_String"
-  ]
-},
-{
-  description: "Causes OutOfMemoryError to test finalization",
-  result: EXEC_FAILED,
-  names: [
-      "org.apache.harmony.tests.java.lang.ref.SoftReferenceTest#test_get_SoftReference",
-      "org.apache.harmony.crypto.tests.javax.crypto#ExemptionMechanismTest#test_finalize"
-  ]
-},
-{
-  description: "Causes open dex file error",
-  modes: [device],
-  names: [
-      "org.apache.harmony.tests.java.lang.reflect.GenericSignatureFormatErrorTest#test_signatureFormatError"
-  ]
-},
-{
-  description: "Requires functional Support_Jetty",
-  bug: 28535961,
-  result: EXEC_FAILED,
-  names: [
-      "com.android.org.apache.harmony.luni.tests.java.net.URLClassLoaderTest"
-  ]
-},
-{
-  description: "Unable to execute Support_AvailTest",
-  result: EXEC_FAILED,
-  bug: 28535603,
-  names: [
-      "com.android.org.apache.harmony.luni.tests.internal.process.SystemProcessTest#test_interrupt"
-  ]
-}
-]
diff --git a/expectations/icebox.txt b/expectations/icebox.txt
deleted file mode 100644
index db9e3ad..0000000
--- a/expectations/icebox.txt
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * This file contains expectations for tests that we'd like to eventually fix, but aren't urgent.
- */
-[
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  name: "libcore.xml.DomTest#testEntityDeclarations",
-  substring: "This implementation does not parse entity declarations"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  name: "libcore.xml.DomTest#testGetWholeTextWithEntityReference",
-  substring: "This implementation doesn't resolve entity references in getWholeText"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  name: "libcore.xml.DomTest#testExpandingEntityReferencesOff",
-  bug: 3268630,
-  substring: "This implementation doesn't include children in entity references"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  name: "libcore.xml.DomTest#testExpandingEntityReferencesOn",
-  bug: 3268630,
-  substring: "This implementation doesn't expand entity references"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  name: "libcore.xml.DomTest#testIsElementContentWhitespaceWithDeclaration",
-  substring: "This implementation does not recognize element content whitespace"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  name: "libcore.xml.DomTest#testNotations",
-  substring: "This implementation does not parse notations"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  names: [
-    "tests.org.w3c.dom.HCNotationsRemoveNamedItemNS#testRemoveNamedItemNS",
-    "tests.org.w3c.dom.HCNotationsSetNamedItemNS#testNotationsSetNamedItemNS"
-  ]
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  name: "libcore.xml.DeclarationTest#testGetXmlEncoding",
-  substring: "This implementation doesn't parse the encoding from the XML declaration"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  name: "libcore.xml.DeclarationTest#testGetXmlStandalone",
-  substring: "This implementation doesn't parse standalone from the XML declaration"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  name: "libcore.xml.DeclarationTest#testGetXmlVersion",
-  substring: "This implementation doesn't parse the version from the XML declaration"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  name: "libcore.xml.NormalizeTest#testSchemaTypeDtd",
-  substring: "This implementation's setParameter() supports an unexpected value: schema-type=http://www.w3.org/TR/REC-xml"
-},
-{
-  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
-  bug: 3268630,
-  name: "org.apache.harmony.tests.javax.xml.parsers.DocumentBuilderTest#testSetEntityResolver",
-  substring: "java.lang.ClassCastException: org.apache.harmony.xml.dom.EntityReferenceImpl"
-},
-{
-  description: "many tests attempt to fork a Java executable, but fork the wrong one",
-  result: "EXEC_FAILED",
-  failure: "should fork a dalvikvm, not a JVM",
-  substring: "/system/bin.*IOException"
-},
-{
-  description: "low-impact XML bugs:",
-  result: EXEC_FAILED,
-  name: "libcore.xml.DomTest#testAttributeNamedIdIsNotAnIdByDefault",
-  substring: "This implementation incorrectly interprets the \"id\" attribute as an identifier by default"
-},
-{
-  description: "low-impact XML bugs:",
-  result: EXEC_FAILED,
-  name: "libcore.xml.DomTest#testDocumentAddChild",
-  substring: "Document nodes shouldn't accept child nodes"
-},
-{
-  description: "low-impact XML bugs:",
-  result: EXEC_FAILED,
-  name: "libcore.xml.DomTest#testElementTraversalFeature",
-  substring: "This implementation is expected to support ElementTraversal v. 1.0 but does not."
-},
-{
-  description: "low-impact XML bugs:",
-  result: EXEC_FAILED,
-  name: "libcore.xml.DomTest#testLoadSaveFeature",
-  substring: "This implementation is expected to support LS v. 3.0 but does not."
-},
-{
-  description: "low-impact XML bugs:",
-  result: EXEC_FAILED,
-  name: "libcore.xml.SaxTest#testYesPrefixesYesNamespaces",
-  substring: "The 'namespace-prefix' feature is not supported while the 'namespaces' feature is enabled."
-},
-{
-  description: "low-impact XML bugs:",
-  result: EXEC_FAILED,
-  name: "org.apache.harmony.tests.javax.xml.parsers.SAXParserFactoryTest#test_newInstance",
-  substring: "Expected FactoryConfigurationError was not thrown"
-},
-{
-  description: "low-impact XML bugs:",
-  result: EXEC_FAILED,
-  names: [
-    "org.apache.harmony.tests.javax.xml.parsers.DocumentBuilderFactoryTest#test_isSetXIncludeAware",
-    "org.apache.harmony.tests.javax.xml.parsers.DocumentBuilderTest#testIsXIncludeAware",
-    "org.apache.harmony.tests.javax.xml.parsers.SAXParserFactoryTest#test_setIsXIncludeAware",
-    "org.apache.harmony.tests.javax.xml.parsers.SAXParserTest#testIsXIncludeAware"
-  ],
-  substring: "java.lang.UnsupportedOperationException: This parser does not support specification \"Unknown\" version \"0.0\""
-},
-{
-  description: "a low-impact bug, also present in Crockford's implementation of org.json",
-  result: EXEC_FAILED,
-  name: "org.json.ParsingTest#test64BitHexValues",
-  substring: "Large hex longs shouldn't be yield ints or strings expected:<-1> but was:<0xFFFFFFFFFFFFFFFF>"
-},
-{
-  description: "this test needs to be fixed. We supply optional qnames, but this test doesn't expect them",
-  result: EXEC_FAILED,
-  name: "org.apache.harmony.tests.javax.xml.parsers.SAXParserTest#test_parseLjava_io_InputStreamLorg_xml_sax_helpers_DefaultHandlerLjava_lang_String"
-},
-{
-  description: "BouncyCastle allows unrecognized algorithms, but RI does not, not clear if this is a bug",
-  result: EXEC_FAILED,
-  name: "org.apache.harmony.crypto.tests.javax.crypto.KeyAgreementTest#test_generateSecretLjava_lang_String",
-  substring: "junit.framework.AssertionFailedError: NoSuchAlgorithmException expected"
-}
-]
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 1c0acf4..2d60453 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1,8 +1,49 @@
 /*
- * This file contains expectations for tests that were annotated with @KnownFailure at the time
+ * This file contains test expectations for libcore.
+ * TODO: Rename this file to account for the fact that it has both tags and known failures
  */
 [
 {
+  description: "large tests",
+  result: SUCCESS,
+  names: [
+    /* libcore tests that take over 15 minutes on device because of DHParametersHelper.generateSafePrimes */
+    "org.apache.harmony.crypto.tests.javax.crypto.func.KeyAgreementFunctionalTest",
+    "org.apache.harmony.crypto.tests.javax.crypto.interfaces.DHPrivateKeyTest",
+    "org.apache.harmony.crypto.tests.javax.crypto.interfaces.DHPublicKeyTest",
+    /* non-AOSP tests http://b/8027066 */
+    "java.util.EnumSet.EnumSetBash",
+    "java.io.PipedInputStream.CloseAndAvailableRC",
+    "java.io.PrintStream.OversynchronizedTest",
+    "java.io.PrintWriter.OversynchronizedTest",
+    "java.lang.String.Split",
+    "java.lang.ref.SoftReference.Pin",
+    "java.math.BigInteger.BigIntegerTest",
+    "java.net.MulticastSocket.Test",
+    "java.net.Socket.InheritTimeout",
+    "java.net.Socket.reset.Test",
+    "java.net.URLConnection.TimeoutTest",
+    "java.nio.channels.DatagramChannel.ConnectedSend",
+    "java.nio.channels.FileChannel.ExpandingMap",
+    "java.nio.channels.FileChannel.Transfers",
+    "java.nio.channels.SocketChannel.Open",
+    "java.text.Bidi.Bug6665028",
+    "java.util.Collections.FindSubList",
+    "java.util.Locale.Bug4518797",
+    "java.util.ResourceBundle.Control.StressTest",
+    "java.util.WeakHashMap.GCDuringIteration",
+    "java.util.concurrent.FutureTask.Throw",
+    "java.util.concurrent.locks.ReentrantReadWriteLock.MapLoops",
+    "java.util.zip.LargeZip",
+    "java.util.zip.ZipFile.LargeZipFile",
+    "java.util.zip.ZipFile.ManyEntries",
+    "libcore.java.lang.SystemTest_testArrayCopyConcurrentModification",
+    "sun.nio.cs.FindOneCharEncoderBugs",
+    "sun.nio.cs.SurrogateGB18030Test"
+  ],
+  "tags": [ "large" ]
+},
+{
   description: "can't compile a pattern with negative look-behind and quantifiers with upper bounds",
   result: EXEC_FAILED,
   name: "org.apache.harmony.regex.tests.java.util.regex.PatternTest#test_bug_40103",
@@ -1505,11 +1546,321 @@
   ]
 },
 {
+  description: "Bouncy Castle doesn't prevent reusing initialization vectors",
+  bug: 31801320,
+  result: EXEC_FAILED,
+  names: [
+    "com.google.security.wycheproof.AesGcmTest#testIvReuse"
+  ]
+},
+{
+  description: "Conscrypt produces different exceptions under different circumstances",
+  bug: 36772622,
+  result: EXEC_FAILED,
+  names: [
+    "com.google.security.wycheproof.RsaEncryptionTest#testExceptionsPKCS1",
+    "com.google.security.wycheproof.RsaEncryptionTest#testGetExceptionsOAEP"
+  ]
+},
+{
+  description: "Conscrypt fails these tests in 32-bit mode",
+  bug: 36636626,
+  result: EXEC_FAILED,
+  names: [
+    "com.google.security.wycheproof.EcdhTest#testModifiedPublic",
+    "com.google.security.wycheproof.EcdhTest#testModifiedPublicSpec"
+  ]
+},
+{
   description: "Bullhead kernel does not block send when buffer is supposed to have saturated",
   bug: 36691333,
   result: EXEC_FAILED,
   names: [
     "libcore.java.net.SocketTimeoutTest#testSocketWriteNeverTimeouts"
   ]
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  name: "libcore.xml.DomTest#testEntityDeclarations",
+  substring: "This implementation does not parse entity declarations"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  name: "libcore.xml.DomTest#testGetWholeTextWithEntityReference",
+  substring: "This implementation doesn't resolve entity references in getWholeText"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  name: "libcore.xml.DomTest#testExpandingEntityReferencesOff",
+  bug: 3268630,
+  substring: "This implementation doesn't include children in entity references"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  name: "libcore.xml.DomTest#testExpandingEntityReferencesOn",
+  bug: 3268630,
+  substring: "This implementation doesn't expand entity references"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  name: "libcore.xml.DomTest#testIsElementContentWhitespaceWithDeclaration",
+  substring: "This implementation does not recognize element content whitespace"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  name: "libcore.xml.DomTest#testNotations",
+  substring: "This implementation does not parse notations"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  names: [
+    "tests.org.w3c.dom.HCNotationsRemoveNamedItemNS#testRemoveNamedItemNS",
+    "tests.org.w3c.dom.HCNotationsSetNamedItemNS#testNotationsSetNamedItemNS"
+  ]
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  name: "libcore.xml.DeclarationTest#testGetXmlEncoding",
+  substring: "This implementation doesn't parse the encoding from the XML declaration"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  name: "libcore.xml.DeclarationTest#testGetXmlStandalone",
+  substring: "This implementation doesn't parse standalone from the XML declaration"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  name: "libcore.xml.DeclarationTest#testGetXmlVersion",
+  substring: "This implementation doesn't parse the version from the XML declaration"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  name: "libcore.xml.NormalizeTest#testSchemaTypeDtd",
+  substring: "This implementation's setParameter() supports an unexpected value: schema-type=http://www.w3.org/TR/REC-xml"
+},
+{
+  description: "Dalvik doesn't support XML Schemas, DTDs or validation",
+  bug: 3268630,
+  name: "org.apache.harmony.tests.javax.xml.parsers.DocumentBuilderTest#testSetEntityResolver",
+  substring: "java.lang.ClassCastException: org.apache.harmony.xml.dom.EntityReferenceImpl"
+},
+{
+  description: "many tests attempt to fork a Java executable, but fork the wrong one",
+  result: "EXEC_FAILED",
+  failure: "should fork a dalvikvm, not a JVM",
+  substring: "/system/bin.*IOException"
+},
+{
+  description: "low-impact XML bugs:",
+  result: EXEC_FAILED,
+  name: "libcore.xml.DomTest#testAttributeNamedIdIsNotAnIdByDefault",
+  substring: "This implementation incorrectly interprets the \"id\" attribute as an identifier by default"
+},
+{
+  description: "low-impact XML bugs:",
+  result: EXEC_FAILED,
+  name: "libcore.xml.DomTest#testDocumentAddChild",
+  substring: "Document nodes shouldn't accept child nodes"
+},
+{
+  description: "low-impact XML bugs:",
+  result: EXEC_FAILED,
+  name: "libcore.xml.DomTest#testElementTraversalFeature",
+  substring: "This implementation is expected to support ElementTraversal v. 1.0 but does not."
+},
+{
+  description: "low-impact XML bugs:",
+  result: EXEC_FAILED,
+  name: "libcore.xml.DomTest#testLoadSaveFeature",
+  substring: "This implementation is expected to support LS v. 3.0 but does not."
+},
+{
+  description: "low-impact XML bugs:",
+  result: EXEC_FAILED,
+  name: "libcore.xml.SaxTest#testYesPrefixesYesNamespaces",
+  substring: "The 'namespace-prefix' feature is not supported while the 'namespaces' feature is enabled."
+},
+{
+  description: "low-impact XML bugs:",
+  result: EXEC_FAILED,
+  name: "org.apache.harmony.tests.javax.xml.parsers.SAXParserFactoryTest#test_newInstance",
+  substring: "Expected FactoryConfigurationError was not thrown"
+},
+{
+  description: "low-impact XML bugs:",
+  result: EXEC_FAILED,
+  names: [
+    "org.apache.harmony.tests.javax.xml.parsers.DocumentBuilderFactoryTest#test_isSetXIncludeAware",
+    "org.apache.harmony.tests.javax.xml.parsers.DocumentBuilderTest#testIsXIncludeAware",
+    "org.apache.harmony.tests.javax.xml.parsers.SAXParserFactoryTest#test_setIsXIncludeAware",
+    "org.apache.harmony.tests.javax.xml.parsers.SAXParserTest#testIsXIncludeAware"
+  ],
+  substring: "java.lang.UnsupportedOperationException: This parser does not support specification \"Unknown\" version \"0.0\""
+},
+{
+  description: "a low-impact bug, also present in Crockford's implementation of org.json",
+  result: EXEC_FAILED,
+  name: "org.json.ParsingTest#test64BitHexValues",
+  substring: "Large hex longs shouldn't be yield ints or strings expected:<-1> but was:<0xFFFFFFFFFFFFFFFF>"
+},
+{
+  description: "this test needs to be fixed. We supply optional qnames, but this test doesn't expect them",
+  result: EXEC_FAILED,
+  name: "org.apache.harmony.tests.javax.xml.parsers.SAXParserTest#test_parseLjava_io_InputStreamLorg_xml_sax_helpers_DefaultHandlerLjava_lang_String"
+},
+{
+  description: "BouncyCastle allows unrecognized algorithms, but RI does not, not clear if this is a bug",
+  result: EXEC_FAILED,
+  name: "org.apache.harmony.crypto.tests.javax.crypto.KeyAgreementTest#test_generateSecretLjava_lang_String",
+  substring: "junit.framework.AssertionFailedError: NoSuchAlgorithmException expected"
+},
+{
+  description: "libcore.java.io.OldFileTest#test_deleteOnExit fails on IRM05 mysid-user",
+  name: "libcore.java.io.OldFileTest#test_deleteOnExit",
+  bug: 5834665
+},
+{
+  description: "We're retiring the security manager. Unfortunately, tests all over the place
+                need to check that they're secure, so they all fail when we refuse to install
+                a security manager. This suppresses all of these failures.",
+  result: EXEC_FAILED,
+  failure: "disable securityManager",
+  pattern: ".*java.lang.SecurityException\\s+at java.lang.System.setSecurityManager.*",
+  bug: 2585285
+},
+{
+  description: "ignore compilation errors due to different available APIs",
+  result: COMPILE_FAILED,
+  failure: "ignore compilation errors",
+  pattern: ".*\\.java:\\d+: cannot find symbol.*"
+},
+{
+  description: "the average length of possible UTF-8 sequences is 2 bytes.",
+  result: EXEC_FAILED,
+  name: "org.apache.harmony.tests.java.nio.charset.UTFCharsetEncoderTest#testSpecificDefaultValue",
+  substring: "junit.framework.AssertionFailedError: expected:<1.1> but was:<2.0>"
+},
+{
+  description: "Some tests (ExcludedProxyTest) connect to a public webserver to check that the HTTP client works",
+  result: EXEC_FAILED,
+  failure: "connect to the Internet",
+  pattern: ".*java.net.UnknownHostException:.*jcltest.apache.org.*"
+},
+{
+  description: "Some tests (ExcludedProxyTest) connect to a public webserver to check that the HTTP client works",
+  result: EXEC_FAILED,
+  names: [
+    "com.android.org.apache.harmony.luni.tests.java.net.ExcludedProxyTest"
+  ]
+},
+{
+  description: "Some tests depend on ICU data, which has changed. Others make assumptions about floating point rounding",
+  result: EXEC_FAILED,
+  names: [
+    "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_DateTimeConversion",
+    "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_GeneralConversionOther",
+    "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_LineSeparator",
+    "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_Percent"
+  ]
+},
+{
+  description: "(Needs investigation) Some tests make assertions that don't make sense, others use broken port allocation logic.",
+  result: EXEC_FAILED,
+  names: [
+    "org.apache.harmony.tests.java.net.InetAddressTest#test_isReachableLjava_net_NetworkInterfaceII_loopbackInterface"
+  ]
+},
+{
+  description: "Potentially flakey because they rely on a specific local TCP port being free.",
+  result: EXEC_FAILED,
+  names: [
+      "org.apache.harmony.tests.java.nio.channels.ServerSocketChannelTest#test_bind_explicitPort"
+  ]
+},
+{
+  description: "The ResourceBundle code under test is probably not used much on Android and needs a lot of attention.",
+  modes: [device],
+  bug: 13747957,
+  names: [
+      "org.apache.harmony.tests.java.util.ControlTest#test_needsReload_LStringLLocaleLStringLClassLoaderResourceBundleJ"
+  ]
+},
+{
+  description: "Fails in CTS, passes in CoreTestRunner.",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: [
+      "org.apache.harmony.tests.java.net.URLConnection#test_getContentEncoding",
+      "libcore.java.text.OldNumberFormatTest#test_parseLjava_lang_String",
+      "libcore.java.nio.channels.OldSocketChannelTest#test_writeLjava_nio_ByteBuffer_Nonblocking_HugeData",
+      "org.apache.harmony.tests.java.lang.ProcessManagerTest#testSleep",
+      "libcore.java.security.cert.OldPKIXParametersTest#testPKIXParametersKeyStore04"
+  ]
+},
+{
+  description: "Suffers from DH slowness, disabling for now.",
+  result: EXEC_FAILED,
+  names: [
+      "libcore.java.security.OldDHTest#testDHGen",
+      "libcore.java.security.OldKeyPairGeneratorTestDH#testKeyPairGenerator",
+      "libcore.javax.crypto.spec.KeyPairGeneratorTestDH#testKeyPairGenerator",
+      "libcore.javax.crypto.spec.AlgorithmParametersTestDH#testAlgorithmParameters",
+      "libcore.javax.crypto.spec.AlgorithmParameterGeneratorTestDH#testAlgorithmParameterGenerator"
+  ]
+},
+{
+  description: "Destroys MD5 provider, hurts succeeding tests",
+  result: EXEC_FAILED,
+  names: [
+      "org.apache.harmony.tests.api.javax.security.cert.X509CertificateTest#testVerifyPublicKey",
+      "org.apache.harmony.tests.api.javax.security.cert.X509CertificateTest#testVerifyPublicKeyString"
+  ]
+},
+{
+  description: "Support_TestWebServer requires isolation.",
+  result: EXEC_FAILED,
+  names: [
+      "libcore.java.net.OldURLClassLoaderTest#test_findResourceLjava_lang_String"
+  ]
+},
+{
+  description: "Causes OutOfMemoryError to test finalization",
+  result: EXEC_FAILED,
+  names: [
+      "org.apache.harmony.tests.java.lang.ref.SoftReferenceTest#test_get_SoftReference",
+      "org.apache.harmony.crypto.tests.javax.crypto#ExemptionMechanismTest#test_finalize"
+  ]
+},
+{
+  description: "Causes open dex file error",
+  modes: [device],
+  names: [
+      "org.apache.harmony.tests.java.lang.reflect.GenericSignatureFormatErrorTest#test_signatureFormatError"
+  ]
+},
+{
+  description: "Requires functional Support_Jetty",
+  bug: 28535961,
+  result: EXEC_FAILED,
+  names: [
+      "com.android.org.apache.harmony.luni.tests.java.net.URLClassLoaderTest"
+  ]
+},
+{
+  description: "Unable to execute Support_AvailTest",
+  result: EXEC_FAILED,
+  bug: 28535603,
+  names: [
+      "com.android.org.apache.harmony.luni.tests.internal.process.SystemProcessTest#test_interrupt"
+  ]
 }
 ]
diff --git a/expectations/taggedtests.txt b/expectations/taggedtests.txt
deleted file mode 100644
index cc2a4d6..0000000
--- a/expectations/taggedtests.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * This file contains expectations for tests that require support from the test runner to complete
- * successfully.
- */
-[
-{
-  description: "large tests",
-  result: SUCCESS,
-  names: [
-    /* libcore tests that take over 15 minutes on device because of DHParametersHelper.generateSafePrimes */
-    "org.apache.harmony.crypto.tests.javax.crypto.func.KeyAgreementFunctionalTest",
-    "org.apache.harmony.crypto.tests.javax.crypto.interfaces.DHPrivateKeyTest",
-    "org.apache.harmony.crypto.tests.javax.crypto.interfaces.DHPublicKeyTest",
-    /* non-AOSP tests http://b/8027066 */
-    "java.util.EnumSet.EnumSetBash",
-    "java.io.PipedInputStream.CloseAndAvailableRC",
-    "java.io.PrintStream.OversynchronizedTest",
-    "java.io.PrintWriter.OversynchronizedTest",
-    "java.lang.String.Split",
-    "java.lang.ref.SoftReference.Pin",
-    "java.math.BigInteger.BigIntegerTest",
-    "java.net.MulticastSocket.Test",
-    "java.net.Socket.InheritTimeout",
-    "java.net.Socket.reset.Test",
-    "java.net.URLConnection.TimeoutTest",
-    "java.nio.channels.DatagramChannel.ConnectedSend",
-    "java.nio.channels.FileChannel.ExpandingMap",
-    "java.nio.channels.FileChannel.Transfers",
-    "java.nio.channels.SocketChannel.Open",
-    "java.text.Bidi.Bug6665028",
-    "java.util.Collections.FindSubList",
-    "java.util.Locale.Bug4518797",
-    "java.util.ResourceBundle.Control.StressTest",
-    "java.util.WeakHashMap.GCDuringIteration",
-    "java.util.concurrent.FutureTask.Throw",
-    "java.util.concurrent.locks.ReentrantReadWriteLock.MapLoops",
-    "java.util.zip.LargeZip",
-    "java.util.zip.ZipFile.LargeZipFile",
-    "java.util.zip.ZipFile.ManyEntries",
-    "libcore.java.lang.SystemTest_testArrayCopyConcurrentModification",
-    "sun.nio.cs.FindOneCharEncoderBugs",
-    "sun.nio.cs.SurrogateGB18030Test"
-  ],
-  "tags": [ "large" ]
-}
-]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
index 19a63af..601d522 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
@@ -19,6 +19,7 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
 import java.io.InputStreamReader;
 import java.io.DataInputStream;
 import java.io.File;
@@ -27,9 +28,16 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Base64;
 import java.util.Locale;
+import libcore.io.IoUtils;
 
 public class PrintStreamTest extends junit.framework.TestCase {
+    private static final String UNICODE_STRING =
+            "K\u03B1\u03BB\u03B7\u00B5\u03B5\u00B4\u03C1\u03B1 \u03BA\u03BF\u00B4\u03C3\u00B5\u03B5";
 
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
 
@@ -70,19 +78,16 @@
      * {@link java.io.PrintStream#PrintStream(String)}
      */
     public void test_Constructor_Ljava_lang_String() throws IOException {
-        MockPrintStream os = new MockPrintStream(testFilePath);
-        assertNotNull(os);
+        PrintStream os = new PrintStream(testFilePath);
+        os.print(UNICODE_STRING);
         os.close();
+        assertFileContents(UNICODE_STRING.getBytes(Charset.defaultCharset()), testFile);
     }
 
     /**
      * {@link java.io.PrintStream#PrintStream(String, String)}
      */
     public void test_Constructor_Ljava_lang_String_Ljava_lang_String() throws Exception {
-        MockPrintStream os = new MockPrintStream(testFilePath, "utf-8");
-        assertNotNull(os);
-        os.close();
-
         // Test that a bogus charset is mentioned in the exception
         try {
             new PrintStream(testFilePath, "Bogus");
@@ -90,6 +95,20 @@
         } catch (UnsupportedEncodingException e) {
             assertNotNull(e.getMessage());
         }
+
+        {
+            PrintStream os = new PrintStream(testFilePath, "utf-8");
+            os.print(UNICODE_STRING);
+            os.close();
+            assertFileContents(UNICODE_STRING.getBytes(StandardCharsets.UTF_8), testFile);
+        }
+
+        {
+            PrintStream os = new PrintStream(testFilePath, "utf-16");
+            os.print(UNICODE_STRING);
+            os.close();
+            assertFileContents(UNICODE_STRING.getBytes(StandardCharsets.UTF_16), testFile);
+        }
     }
 
     /**
@@ -124,7 +143,7 @@
     /**
      * java.io.PrintStream#PrintStream(java.io.OutputStream, boolean, String)
      */
-    public void test_ConstructorLjava_io_OutputStreamZLjava_lang_String() {
+    public void test_ConstructorLjava_io_OutputStreamZLjava_lang_String() throws Exception {
         try {
             new PrintStream(new ByteArrayOutputStream(), false,
                     "%Illegal_name!");
@@ -132,6 +151,24 @@
         } catch (UnsupportedEncodingException e) {
             // expected
         }
+
+        {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            PrintStream printStream = new PrintStream(bos, true /* autoFlush */, "utf-8");
+            printStream.print(UNICODE_STRING);
+            printStream.close();
+            assertByteArraysEqual(UNICODE_STRING.getBytes(StandardCharsets.UTF_8),
+                    bos.toByteArray());
+        }
+
+        {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            PrintStream printStream = new PrintStream(bos, true /* autoFlush */, "utf-16");
+            printStream.print(UNICODE_STRING);
+            printStream.close();
+            assertByteArraysEqual(UNICODE_STRING.getBytes(StandardCharsets.UTF_16),
+                    bos.toByteArray());
+        }
     }
 
     /**
@@ -626,6 +663,59 @@
     }
 
     /**
+     * Tests that a PrintStream with {@code autoFlush == true} will call
+     * {@link OutputStream#flush()} at least once, after the last byte
+     * was written.
+     */
+    public void test_autoFlush_flushesEverything() {
+        CountFlushOutputStream counter = new CountFlushOutputStream(new ByteArrayOutputStream());
+        PrintStream printStream = new PrintStream(counter, true /* autoFlush */);
+        printStream.print("Hello, world!");
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.print(Math.PI);
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.print("\n");
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.println();
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.println("Lots\nof\nnewlines\n");
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.print("Line 1\nLine 2\n".toCharArray());
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+
+        byte[] bytes = "Line without a newline".getBytes(StandardCharsets.UTF_8);
+        printStream.write(bytes, 0, bytes.length);
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+    }
+
+    /**
+     * Tests that a PrintStream with {@code autoFlush == false} will not
+     * call {@link OutputStream#flush()} in regular (non-error) operation.
+     */
+    public void test_noAutoFlush() {
+        CountFlushOutputStream counter = new CountFlushOutputStream(new ByteArrayOutputStream());
+        PrintStream printStream = new PrintStream(counter, false /* autoFlush */);
+        printStream.print("Hello, world!");
+        printStream.print(Math.PI);
+        printStream.print("\n");
+        printStream.println();
+        printStream.println("Lots\nof\nnewlines\n");
+        printStream.print("Line 1\nLine 2\n".toCharArray());
+        byte[] bytes = "Line without a newline".getBytes(StandardCharsets.UTF_8);
+        printStream.write(bytes, 0, bytes.length);
+        assertFalse(counter.hasEverBeenFlushed());
+        assertFalse(counter.hasBeenFlushedSinceLastWrite());
+
+        // checkError() still causes the PrintStream to flush(), even when autoFlush == false.
+        printStream.checkError();
+        assertTrue(counter.hasEverBeenFlushed());
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.print("This data\nwill not be flushed.");
+        assertTrue(counter.hasEverBeenFlushed());
+        assertFalse(counter.hasBeenFlushedSinceLastWrite());
+    }
+
+    /**
      * java.io.PrintStream#printf(java.lang.String, java.lang.Object...)
      */
     public void test_printfLjava_lang_String$Ljava_lang_Object() {
@@ -669,5 +759,47 @@
         super.tearDown();
     }
 
+    private static void assertByteArraysEqual(byte[] expected, byte[] actual) {
+        String message = "Expected " + Base64.getEncoder().encodeToString(expected) + ", got: "
+                + Base64.getEncoder().encodeToString(actual);
+        assertTrue(message, Arrays.equals(actual, expected));
+    }
+
+    private static void assertFileContents(byte[] expected, File file) throws IOException {
+        byte[] actual = IoUtils.readFileAsByteArray(file.getAbsolutePath());
+        assertByteArraysEqual(expected, actual);
+    }
+
+    static class CountFlushOutputStream extends FilterOutputStream {
+        private boolean hasBeenFlushedSinceLastWrite = false;
+        private boolean hasEverBeenFlushed = false;
+
+        public CountFlushOutputStream(OutputStream delegate) {
+            super(delegate);
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            super.write(b);
+            hasBeenFlushedSinceLastWrite = false;
+        }
+
+        @Override
+        public void flush() throws IOException {
+            super.flush();
+            hasBeenFlushedSinceLastWrite = true;
+            hasEverBeenFlushed = true;
+        }
+
+        /** Whether {@link #flush()} has been called since the last write. */
+        public boolean hasBeenFlushedSinceLastWrite() {
+            return hasBeenFlushedSinceLastWrite;
+        }
+
+        /** Whether {@link #flush()} has ever been called after this stream was constructed. */
+        public boolean hasEverBeenFlushed() {
+            return hasEverBeenFlushed;
+        }
+    }
 
 }
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index 20a4a47..2e6fc1b 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -357,6 +357,7 @@
     public static final int MS_ASYNC = placeholder();
     public static final int MS_INVALIDATE = placeholder();
     public static final int MS_SYNC = placeholder();
+    /** @hide */ public static final int NETLINK_NETFILTER = placeholder();
     /** @hide */ public static final int NETLINK_ROUTE = placeholder();
     public static final int NI_DGRAM = placeholder();
     public static final int NI_NAMEREQD = placeholder();
diff --git a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
index a981c18..3d12664 100644
--- a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
+++ b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
@@ -74,6 +74,7 @@
             byte[] replacement = makeReplacement(icuCanonicalName, address);
             CharsetEncoderICU result = new CharsetEncoderICU(cs, averageBytesPerChar, maxBytesPerChar, replacement, address);
             address = 0; // CharsetEncoderICU has taken ownership; its finalizer will do the free.
+            result.updateCallback();
             return result;
         } finally {
             if (address != 0) {
@@ -97,7 +98,6 @@
         // Our native peer needs to know what just happened...
         this.converterHandle = address;
         NativeConverter.registerConverter(this, converterHandle);
-        updateCallback();
     }
 
     @Override protected void implReplaceWith(byte[] newReplacement) {
diff --git a/luni/src/main/java/libcore/icu/TimeZoneNames.java b/luni/src/main/java/libcore/icu/TimeZoneNames.java
index 917d9ce..68e6e30 100644
--- a/luni/src/main/java/libcore/icu/TimeZoneNames.java
+++ b/luni/src/main/java/libcore/icu/TimeZoneNames.java
@@ -43,15 +43,6 @@
     public static final int NAME_COUNT = 5;
 
     private static final ZoneStringsCache cachedZoneStrings = new ZoneStringsCache();
-    static {
-        // Ensure that we pull in the zone strings for the root locale, en_US, and the
-        // user's default locale. (All devices must support the root locale and en_US,
-        // and they're used for various system things like HTTP headers.) Pre-populating
-        // the cache is especially useful on Android because we'll share this via the Zygote.
-        cachedZoneStrings.get(Locale.ROOT);
-        cachedZoneStrings.get(Locale.US);
-        cachedZoneStrings.get(Locale.getDefault());
-    }
 
     public static class ZoneStringsCache extends BasicLruCache<Locale, String[][]> {
         public ZoneStringsCache() {
@@ -71,6 +62,7 @@
             fillZoneStrings(locale.toLanguageTag(), result);
             long nativeEnd = System.nanoTime();
 
+            addOffsetStrings(result);
             internStrings(result);
             // Ending up in this method too often is an easy way to make your app slow, so we ensure
             // it's easy to tell from the log (a) what we were doing, (b) how long it took, and
@@ -83,8 +75,33 @@
             return result;
         }
 
+        /**
+         * Generate offset strings for cases where we don't have a name. Note that this is a
+         * potentially slow operation, as we need to load the timezone data for all affected
+         * time zones.
+         */
+        private void addOffsetStrings(String[][] result) {
+            for (int i = 0; i < result.length; ++i) {
+                TimeZone tz = null;
+                for (int j = 1; j < NAME_COUNT; ++j) {
+                    if (result[i][j] != null) {
+                        continue;
+                    }
+                    if (tz == null) {
+                        tz = TimeZone.getTimeZone(result[i][0]);
+                    }
+                    int offsetMillis = tz.getRawOffset();
+                    if (j == LONG_NAME_DST || j == SHORT_NAME_DST) {
+                        offsetMillis += tz.getDSTSavings();
+                    }
+                    result[i][j] = TimeZone.createGmtOffsetString(
+                            /* includeGmt */ true, /*includeMinuteSeparator */true, offsetMillis);
+                }
+            }
+        }
+
         // De-duplicate the strings (http://b/2672057).
-        private synchronized void internStrings(String[][] result) {
+        private void internStrings(String[][] result) {
             HashMap<String, String> internTable = new HashMap<String, String>();
             for (int i = 0; i < result.length; ++i) {
                 for (int j = 1; j < NAME_COUNT; ++j) {
diff --git a/luni/src/main/java/libcore/net/MimeUtils.java b/luni/src/main/java/libcore/net/MimeUtils.java
index b746273..693b6da 100644
--- a/luni/src/main/java/libcore/net/MimeUtils.java
+++ b/luni/src/main/java/libcore/net/MimeUtils.java
@@ -51,8 +51,7 @@
         add("application/mathematica", "nb");
         add("application/msaccess", "mdb");
         add("application/oda", "oda");
-        add("application/ogg", "ogg");
-        add("application/ogg", "oga");
+        add("application/ogg", "ogx");
         add("application/pdf", "pdf");
         add("application/pgp-keys", "key");
         add("application/pgp-signature", "pgp");
@@ -240,6 +239,9 @@
         add("audio/mpeg", "mp2");
         add("audio/mpeg", "m4a");
         add("audio/mpegurl", "m3u");
+        add("audio/ogg", "oga");
+        add("audio/ogg", "ogg");
+        add("audio/ogg", "spx");
         add("audio/prs.sid", "sid");
         add("audio/x-aiff", "aif");
         add("audio/x-aiff", "aiff");
@@ -372,6 +374,7 @@
         add("video/mpeg", "mpe");
         add("video/mp4", "mp4");
         add("video/mpeg", "VOB");
+        add("video/ogg", "ogv");
         add("video/quicktime", "qt");
         add("video/quicktime", "mov");
         add("video/vnd.mpegurl", "mxu");
diff --git a/luni/src/main/java/libcore/util/TimeZoneFinder.java b/luni/src/main/java/libcore/util/TimeZoneFinder.java
index 4e47df4..37e3b4a 100644
--- a/luni/src/main/java/libcore/util/TimeZoneFinder.java
+++ b/luni/src/main/java/libcore/util/TimeZoneFinder.java
@@ -80,6 +80,7 @@
 
     // VisibleForTesting
     public static TimeZoneFinder createInstanceWithFallback(String... tzLookupFilePaths) {
+        IOException lastException = null;
         for (String tzLookupFilePath : tzLookupFilePaths) {
             try {
                 // We assume that any file in /data was validated before install, and the system
@@ -87,12 +88,18 @@
                 // validation cost here.
                 return createInstance(tzLookupFilePath);
             } catch (IOException e) {
-                System.logE("Unable to process file: " + tzLookupFilePath + " Trying next one.", e);
+                // There's expected to be two files, and it's normal for the first file not to
+                // exist so we don't log, but keep the lastException so we can log it if there
+                // are no valid files available.
+                if (lastException != null) {
+                    e.addSuppressed(lastException);
+                }
+                lastException = e;
             }
         }
 
         System.logE("No valid file found in set: " + Arrays.toString(tzLookupFilePaths)
-                + " Falling back to empty map.");
+                + " Printing exceptions and falling back to empty map.", lastException);
         return createInstanceForTests("<timezones><countryzones /></timezones>");
     }
 
@@ -124,8 +131,8 @@
     }
 
     /**
-     * Return a time zone that has / would have had the specified offset and DST value at the
-     * specified moment in the specified country.
+     * Returns a frozen ICU time zone that has / would have had the specified offset and DST value
+     * at the specified moment in the specified country.
      *
      * <p>In order to be considered a configured zone must match the supplied offset information.
      *
@@ -186,10 +193,11 @@
     }
 
     /**
-     * Returns a list of time zones known to be used in the specified country. If the country code
-     * is not recognized or there is an error during lookup this can return null. The TimeZones
-     * returned will never contain {@link TimeZone#UNKNOWN_ZONE}. This method can return an empty
-     * list in a case when the underlying configuration references only unknown zone IDs.
+     * Returns an immutable list of frozen ICU time zones known to be used in the specified country.
+     * If the country code is not recognized or there is an error during lookup this can return
+     * null. The TimeZones returned will never contain {@link TimeZone#UNKNOWN_ZONE}. This method
+     * can return an empty list in a case when the underlying configuration references only unknown
+     * zone IDs.
      */
     public List<TimeZone> lookupTimeZonesByCountry(String countryIso) {
         synchronized(this) {
diff --git a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
index d30e7a3..c4f25e0 100644
--- a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
+++ b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
@@ -46,10 +46,7 @@
 }
 
 static bool setStringArrayElement(JNIEnv* env, jobjectArray array, int i, const icu::UnicodeString& s) {
-  // Fill in whatever we got. We don't use the display names if they're "GMT[+-]xx:xx"
-  // because icu4c doesn't use the up-to-date time zone transition data, so it gets these
-  // wrong. TimeZone.getDisplayName creates accurate names on demand.
-  // TODO: investigate whether it's worth doing that work once in the Java wrapper instead of on-demand.
+  // Don't use "GMT" string, for backwards compatibility.
   static const icu::UnicodeString kGmt("GMT", 3, US_INV);
   if (!s.isBogus() && !s.startsWith(kGmt)) {
     ScopedLocalRef<jstring> javaString(env, env->NewString(s.getBuffer(), s.length()));
diff --git a/luni/src/test/java/dalvik/system/DexClassLoaderTest.java b/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
index 625cfa9..a99cc23 100644
--- a/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
+++ b/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
@@ -16,8 +16,6 @@
 
 package dalvik.system;
 
-import java.io.FilenameFilter;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -37,7 +35,6 @@
     private File dex2;
     private File jar1;
     private File jar2;
-    private File optimizedDir;
 
     protected void setUp() throws Exception {
         srcDir = File.createTempFile("src", "");
@@ -53,15 +50,10 @@
         copyResource("loading-test2.dex", dex2);
         copyResource("loading-test.jar", jar1);
         copyResource("loading-test2.jar", jar2);
-
-        optimizedDir = File.createTempFile("optimized", "");
-        assertTrue(optimizedDir.delete());
-        assertTrue(optimizedDir.mkdirs());
     }
 
     protected void tearDown() {
         cleanUpDir(srcDir);
-        cleanUpDir(optimizedDir);
     }
 
     private static void cleanUpDir(File dir) {
@@ -99,13 +91,6 @@
         }
     }
 
-    static final FilenameFilter DEX_FILE_NAME_FILTER = new FilenameFilter() {
-        @Override
-        public boolean accept(File file, String s) {
-            return s.endsWith(".dex");
-        }
-    };
-
     /**
      * Helper to construct a DexClassLoader instance to test.
      *
@@ -118,7 +103,7 @@
         for (int i = 1; i < files.length; i++) {
             path += File.pathSeparator + files[i].getAbsolutePath();
         }
-        return new DexClassLoader(path, optimizedDir.getAbsolutePath(), null,
+        return new DexClassLoader(path, null, null,
             ClassLoader.getSystemClassLoader());
     }
 
diff --git a/luni/src/test/java/libcore/java/lang/OldThreadGroupTest.java b/luni/src/test/java/libcore/java/lang/OldThreadGroupTest.java
index 206fdce..35e366e 100644
--- a/luni/src/test/java/libcore/java/lang/OldThreadGroupTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldThreadGroupTest.java
@@ -67,6 +67,8 @@
     }
 
     private ThreadGroup initialThreadGroup = null;
+    // A thread that runs in initialThreadGroup throughout each test.
+    private MyThread initialThread;
     private List<MyThread> myThreads;
 
     public void test_activeGroupCount() {
@@ -100,27 +102,14 @@
                 tg.allowThreadSuspension(true));
     }
 
-    /*
-     * Checks whether the current Thread is in the given list.
-     */
-    private boolean inListOfThreads(Thread[] threads) {
-        for (int i = 0; i < threads.length; i++) {
-            if (Thread.currentThread() == threads[i]) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
     public void test_enumerateLThreadArray() {
         int numThreads = initialThreadGroup.activeCount();
         Thread[] listOfThreads = new Thread[numThreads];
 
         int countThread = initialThreadGroup.enumerate(listOfThreads);
         assertEquals(numThreads, countThread);
-        assertTrue("Current thread must be in enumeration of threads",
-                inListOfThreads(listOfThreads));
+        assertTrue("Initial thread must be in enumeration of threads",
+                Arrays.asList(listOfThreads).contains(initialThread));
     }
 
     public void test_enumerateLThreadArrayLZtest_enumerateLThreadArrayLZ() throws Exception {
@@ -129,14 +118,14 @@
         Thread[] initialThreads = new Thread[initialThreadCount];
         assertEquals(initialThreadCount, initialThreadGroup.enumerate(initialThreads, false));
         assertEquals(initialThreadCount, initialThreadGroup.enumerate(initialThreads, true));
-        assertTrue(inListOfThreads(initialThreads));
+        assertTrue(Arrays.asList(initialThreads).contains(initialThread));
 
         // start some the threads and see how the count changes
         ThreadGroup group = new ThreadGroup(initialThreadGroup, "enumerateThreadArray");
         int groupSize = 3;
         List<MyThread> newThreads = populateGroupsWithThreads(group, groupSize);
         assertEquals(initialThreadCount, initialThreadGroup.enumerate(initialThreads, true));
-        assertTrue(inListOfThreads(initialThreads));
+        assertTrue(Arrays.asList(initialThreads).contains(initialThread));
         for(MyThread thread : newThreads) {
             thread.start();
         }
@@ -148,7 +137,7 @@
         Thread[] afterStartThreads = new Thread[afterStartCount];
         assertEquals(afterStartCount, initialThreadGroup.enumerate(afterStartThreads, true));
         assertEquals(initialPlusNew, new HashSet<Thread>(Arrays.asList(afterStartThreads)));
-        assertTrue(inListOfThreads(afterStartThreads));
+        assertTrue(Arrays.asList(afterStartThreads).contains(initialThread));
 
         // kill the threads and count 'em again
         for(MyThread thread : newThreads) {
@@ -159,7 +148,7 @@
         Thread[] afterDeathThreads = new Thread[afterDeathCount];
         assertEquals(afterDeathCount, initialThreadGroup.enumerate(afterDeathThreads, false));
         assertEquals(Arrays.asList(initialThreads), Arrays.asList(afterDeathThreads));
-        assertTrue(inListOfThreads(afterDeathThreads));
+        assertTrue(Arrays.asList(afterDeathThreads).contains(initialThread));
     }
 
     public void test_enumerateLThreadGroupArray() {
@@ -167,7 +156,7 @@
         ThreadGroup childGroup = new ThreadGroup(initialThreadGroup, "child group");
 
         int numChildGroupsAfter = initialThreadGroup.activeGroupCount();
-        assertTrue(initialThreadGroup.toString(), numChildGroupsAfter == numChildGroupsBefore + 1);
+        assertEquals(initialThreadGroup.toString(), numChildGroupsBefore + 1, numChildGroupsAfter);
         ThreadGroup[] listOfGroups = new ThreadGroup[numChildGroupsAfter];
 
         int countGroupThread = initialThreadGroup.enumerate(listOfGroups);
@@ -183,12 +172,12 @@
         countGroupThread = initialThreadGroup.enumerate(listOfGroups2);
         assertEquals(numChildGroupsAfter - 1, countGroupThread);
 
-        ThreadGroup thrGroup1 = new ThreadGroup("Test Group 1");
+        ThreadGroup thrGroup1 = new ThreadGroup(initialThreadGroup, "Test Group 1");
         countGroupThread = thrGroup1.enumerate(listOfGroups);
         assertEquals(0, countGroupThread);
 
         childGroup.destroy();
-        assertTrue(initialThreadGroup.activeGroupCount() == numChildGroupsBefore + 1);
+        assertEquals(numChildGroupsBefore + 1, initialThreadGroup.activeGroupCount());
      }
 
     public void test_enumerateLThreadGroupArrayLZ() {
@@ -240,6 +229,11 @@
         assertEquals(1, thrGroup.enumerate(listOfGroups, false));
     }
 
+    public void test_getParent() {
+        assertEquals(Thread.currentThread().getThreadGroup(), new ThreadGroup("test").getParent());
+        assertEquals(initialThreadGroup, new ThreadGroup(initialThreadGroup, "test").getParent());
+    }
+
     /**
      * java.lang.ThreadGroup#interrupt()
      */
@@ -326,7 +320,11 @@
     @Override
     protected void setUp() {
         myThreads = new ArrayList<>();
-        initialThreadGroup = Thread.currentThread().getThreadGroup();
+        initialThreadGroup = new ThreadGroup(Thread.currentThread().getThreadGroup(), "test group");
+        initialThread = new MyThread(initialThreadGroup, "initial thread");
+        myThreads.add(initialThread);
+        initialThread.start();
+
         ThreadGroup rootThreadGroup = initialThreadGroup;
         while (rootThreadGroup.getParent() != null) {
             rootThreadGroup = rootThreadGroup.getParent();
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/README.txt b/luni/src/test/java/libcore/java/lang/reflect/parameter/README.txt
index 6d5a6c2..90a40df 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/parameter/README.txt
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/README.txt
@@ -8,7 +8,7 @@
 Regenerate the .dex files with:
 
 make smali
-smali libcore/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetdataTestClasses*.smali \
+smali assemble libcore/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetdataTestClasses*.smali \
     -o libcore/luni/src/test/resources/libcore/java/lang/reflect/parameter/parameter_metadata_test_classes.dex
 
 For reference, the valid smali code should be (roughly) the equivalent of the
diff --git a/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
index 435dce2..74948f6 100644
--- a/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java
@@ -42,16 +42,13 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.Random;
-import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
- import sun.net.ftp.FtpLoginException;
+import sun.net.ftp.FtpLoginException;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
@@ -61,10 +58,10 @@
 public class FtpURLConnectionTest extends TestCase {
 
     private static final String FILE_PATH = "test/file/for/FtpURLConnectionTest.txt";
-    private static final String USER = "user";
-    private static final String PASSWORD = "password";
     private static final String SERVER_HOSTNAME = "localhost";
-    private static final String USER_HOME_DIR = "/home/user";
+    private static final String VALID_USER = "user";
+    private static final String VALID_PASSWORD = "password";
+    private static final String VALID_USER_HOME_DIR = "/home/user";
 
     private FakeFtpServer fakeFtpServer;
     private UnixFakeFileSystem fileSystem;
@@ -74,10 +71,11 @@
         super.setUp();
         fakeFtpServer = new FakeFtpServer();
         fakeFtpServer.setServerControlPort(0 /* allocate port number automatically */);
-        fakeFtpServer.addUserAccount(new UserAccount(USER, PASSWORD, USER_HOME_DIR));
+        fakeFtpServer.addUserAccount(new UserAccount(VALID_USER, VALID_PASSWORD,
+                VALID_USER_HOME_DIR));
         fileSystem = new UnixFakeFileSystem();
         fakeFtpServer.setFileSystem(fileSystem);
-        fileSystem.add(new DirectoryEntry(USER_HOME_DIR));
+        fileSystem.add(new DirectoryEntry(VALID_USER_HOME_DIR));
         fakeFtpServer.start();
     }
 
@@ -89,17 +87,45 @@
 
     public void testInputUrl() throws Exception {
         byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
-        URL fileUrl = addFileEntry(FILE_PATH, fileContents);
+        addFileEntry(FILE_PATH, fileContents);
+        URL fileUrl = getFileUrlWithCredentials(VALID_USER, VALID_PASSWORD, FILE_PATH);
         URLConnection connection = fileUrl.openConnection();
         assertContents(fileContents, connection.getInputStream());
     }
 
+    public void testInputUrl_invalidUserOrPassword() throws Exception {
+        checkInputUrl_invalidUserOrPassword("wrong_user", VALID_PASSWORD);
+        checkInputUrl_invalidUserOrPassword(VALID_USER, "wrong password");
+    }
+
+    public void testInputUrl_missingPassword() throws Exception {
+        URL noPasswordUrl = getFileUrlWithCredentials(VALID_USER, null, FILE_PATH);
+        URLConnection noPasswordConnection = noPasswordUrl.openConnection();
+        try {
+            noPasswordConnection.getInputStream();
+            fail();
+        } catch (IOException expected) {
+        }
+    }
+
+    private void checkInputUrl_invalidUserOrPassword(String user, String password)
+            throws IOException {
+        URL fileUrl = getFileUrlWithCredentials(user, password, FILE_PATH);
+        URLConnection connection = fileUrl.openConnection();
+        try {
+            connection.getInputStream();
+            fail();
+        } catch (sun.net.ftp.FtpLoginException expected) {
+            assertEquals("Invalid username/password", expected.getMessage());
+        }
+    }
+
     public void testOutputUrl() throws Exception {
         byte[] fileContents = "abcdef 1234567890".getBytes(UTF_8);
         addFileEntry("test/output-url/existing file.txt", fileContents);
         byte[] newFileContents = "contents of brand new file".getBytes(UTF_8);
         String filePath = "test/output-url/file that is newly created.txt";
-        URL fileUrl = new URL(getFileUrlString(filePath));
+        URL fileUrl = getFileUrlWithCredentials(VALID_USER, VALID_PASSWORD, filePath);
         URLConnection connection = fileUrl.openConnection();
         connection.setDoInput(false);
         connection.setDoOutput(true);
@@ -223,8 +249,36 @@
         }
     }
 
+    // http://b/35784677
+    public void testCRLFInUserinfo() throws Exception {
+        int serverPort = fakeFtpServer.getServerControlPort();
+        List<String> encodedUserInfos = Arrays.asList(
+                // '\r\n' in the username with password
+                "user%0D%0Acommand:password",
+                // '\r\n' in the password
+                "user:password%0D%0Acommand",
+                // just '\n' in the password
+                "user:password%0Acommand",
+                // just '\n' in the username
+                "user%0Acommand:password"
+        );
+        for (String encodedUserInfo : encodedUserInfos) {
+            String urlString = String.format(Locale.US, "ftp://%s@%s:%s/%s",
+                    encodedUserInfo, SERVER_HOSTNAME, serverPort, FILE_PATH);
+            try {
+                new URL(urlString).openConnection().connect();
+                fail("Connection shouldn't have succeeded: " + urlString);
+            } catch (FtpLoginException expected) {
+                // The original message "Illegal carriage return" gets lost
+                // where FtpURLConnection.connect() translates the
+                // original FtpProtocolException into FtpLoginException.
+                assertEquals("Invalid username/password", expected.getMessage());
+            }
+        }
+    }
+
     private InputStream openFileSystemContents(String fileName) throws IOException {
-        String fullFileName = USER_HOME_DIR + "/" + fileName;
+        String fullFileName = VALID_USER_HOME_DIR + "/" + fileName;
         FileEntry entry = (FileEntry) fileSystem.getEntry(fullFileName);
         assertNotNull("File must exist with name " + fullFileName, entry);
         return entry.createInputStream();
@@ -249,61 +303,13 @@
         }
     }
 
-    // http://b/35784677
-    public void testCRLFInUserinfo() throws Exception {
-        List<String> encodedUserInfos = Arrays.asList(
-                // '\r\n' in the username with password
-                "user%0D%0Acommand:password",
-                // '\r\n' in the password
-                "user:password%0D%0Acommand",
-                // just '\n' in the password
-                "user:password%0Acommand",
-                // just '\n' in the username
-                "user%0Acommand:password"
-        );
-        for (String encodedUserInfo : encodedUserInfos) {
-            ExecutorService executor = Executors.newSingleThreadExecutor();
-            ServerSocket mockFtpServerSocket = new ServerSocket(0);
-            Future<Void> future = executor.submit(new Callable<Void>() {
-                @Override public Void call() throws Exception {
-                    Socket clientSocket = mockFtpServerSocket.accept();
-                    clientSocket.getOutputStream().write("220 o/".getBytes());
-                    clientSocket.close();
-                    return null;
-                }
-              });
-            executor.shutdown();
-
-            String urlString = String.format(Locale.US, "ftp://%s@%s:%s/%s",
-                    encodedUserInfo, SERVER_HOSTNAME, mockFtpServerSocket.getLocalPort(), FILE_PATH);
-            try {
-                new URL(urlString).openConnection().connect();
-                fail("Connection shouldn't have succeeded: " + urlString);
-            } catch (FtpLoginException expected) {
-                // The original message "Illegal carriage return" gets lost
-                // where FtpURLConnection.connect() translates the
-                // original FtpProtocolException into FtpLoginException.
-                assertEquals("Invalid username/password", expected.getMessage());
-            }
-
-            // Cleanup
-            future.get();
-            mockFtpServerSocket.close();
-        }
-    }
-
-    private String getFileUrlString(String filePath) {
+    private URL getFileUrlWithCredentials(String user, String password, String filePath) {
+        Objects.requireNonNull(user);
+        Objects.requireNonNull(filePath);
         int serverPort = fakeFtpServer.getServerControlPort();
-        String urlString = String.format(Locale.US, "ftp://%s:%s@%s:%s/%s",
-                USER, PASSWORD, SERVER_HOSTNAME, serverPort, filePath);
-        return urlString;
-    }
-
-    private URL addFileEntry(String filePath, byte[] fileContents) {
-        FileEntry fileEntry = new FileEntry(USER_HOME_DIR + "/" + filePath);
-        fileEntry.setContents(fileContents);
-        fileSystem.add(fileEntry);
-        String urlString = getFileUrlString(filePath);
+        String credentials = user + (password == null ? "" : (":" + password));
+        String urlString = String.format(Locale.US, "ftp://%s@%s:%s/%s",
+                credentials, SERVER_HOSTNAME, serverPort, filePath);
         try {
             return new URL(urlString);
         } catch (MalformedURLException e) {
@@ -312,6 +318,13 @@
         }
     }
 
+    private URL addFileEntry(String filePath, byte[] fileContents) {
+        FileEntry fileEntry = new FileEntry(VALID_USER_HOME_DIR + "/" + filePath);
+        fileEntry.setContents(fileContents);
+        fileSystem.add(fileEntry);
+        return getFileUrlWithCredentials(VALID_USER, VALID_PASSWORD, filePath);
+    }
+
     /**
      * A {@link ProxySelector} that selects the same (given) Proxy for all URIs.
      */
diff --git a/luni/src/test/java/libcore/java/text/OldBidiTest.java b/luni/src/test/java/libcore/java/text/OldBidiTest.java
index fe8b6cb..08edbcd 100644
--- a/luni/src/test/java/libcore/java/text/OldBidiTest.java
+++ b/luni/src/test/java/libcore/java/text/OldBidiTest.java
@@ -205,4 +205,35 @@
         assertFalse("Latin bidi is mixed: " + latin, latin.isMixed());
         assertTrue("latin bidi is not left to right: " + latin, latin.isLeftToRight());
     }
+
+    // Regression test for http://b/34320622 - when specifying "embeddings" of 0 with RTL characters
+    // and a default of LTR we should not get an exception.
+    public void testEmbeddings() throws Exception {
+        char[] text = new char[2];
+        text[0] = '\u202d'; // LEFT-TO-RIGHT OVERRIDE
+        text[1] = '\u05d0'; // HEBREW LETTER ALEF
+
+        byte[] embeddings = new byte[2];
+        embeddings[0] = 0;
+        embeddings[1] = 0;
+        int flags = Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
+
+        // This threw an exception on N.
+        Bidi bidi = new Bidi(text, 0, embeddings, 0, 2, flags);
+
+        // Assert properties of the resulting Bidi and embeddings array. The results are somewhat
+        // arbitrary and it's hard to know the user's expectations for the characters chosen, but
+        // a failure will identify unintended behavior changes.
+        assertEquals(text.length, bidi.getLength());
+        assertEquals(1, bidi.getBaseLevel());
+        assertEquals(1, bidi.getRunCount());
+        assertEquals(1, bidi.getLevelAt(0));
+        assertEquals(1, bidi.getLevelAt(1));
+        assertEquals(1, bidi.getRunLevel(0));
+        assertEquals(0, bidi.getRunStart(0));
+        assertEquals(2, bidi.getRunLimit(0));
+
+        assertEquals(0, embeddings[0]);
+        assertEquals(0, embeddings[1]);
+    }
 }
diff --git a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
index 20fa986..d1deae1 100644
--- a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
@@ -583,4 +583,33 @@
         assertNull(parsed);
         assertEquals("Wrong error index", 5, pos.getErrorIndex());
     }
+
+    // http://b/38396219
+    public void testDisplayNamesOnNonGregorianCalendar() {
+        assertEquals("Jan", formatDateNonGregorianCalendar("MMM")); // MONTH
+        assertEquals("Jan", formatDateNonGregorianCalendar("LLL")); // MONTH_STANDALONE
+        assertEquals("Thu", formatDateNonGregorianCalendar("EEE")); // DAY_OF_WEEK
+        assertEquals("Thu", formatDateNonGregorianCalendar("ccc")); // STANDALONE_DAY_OF_WEEK
+    }
+
+    /**
+     * Format a date using a "non-gregorian" calendar. This means that we use a calendar that is not
+     * exactly {@code java.util.GregorianCalendar} as checked by
+     * {@link SimpleDateFormat#isGregorianCalendar()}.
+     */
+    private static String formatDateNonGregorianCalendar(String fmt) {
+        DateFormat dateFormat = new SimpleDateFormat(fmt, Locale.US);
+        NonGregorianCalendar cal = new NonGregorianCalendar();
+        cal.clear();
+        cal.setTimeZone(UTC);
+        dateFormat.setCalendar(cal);
+        return dateFormat.format(new Date(0));
+    }
+
+    /**
+     * Calendar that pretends that it's not a GregorianCalendar, for {@link
+     * #testDisplayNamesOnNonGregorianCalendar()}.
+     */
+    private static class NonGregorianCalendar extends GregorianCalendar {
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 375eb36..9f7267c 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -384,6 +384,18 @@
         }
     }
 
+    // http://b/33197219
+    public void testDisplayNameForNonCanonicalTimezones() {
+        TimeZone canonical = TimeZone.getTimeZone("Europe/London");
+        TimeZone nonCanonical = TimeZone.getTimeZone("GB");
+
+        // verify that GB is actually an alias for Europe/London
+        assertTrue(canonical.hasSameRules(nonCanonical));
+
+        assertEquals(canonical.getDisplayName(true, TimeZone.LONG, Locale.ENGLISH),
+                nonCanonical.getDisplayName(true, TimeZone.LONG, Locale.ENGLISH));
+    }
+
     // http://b/30937209
     public void testSetDefaultDeadlock() throws InterruptedException, BrokenBarrierException {
         // Since this tests a deadlock, the test has two fundamental problems:
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
index 1ddeacb..ebf72f0 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
@@ -20,6 +20,7 @@
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.io.InputStream;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.SocketException;
@@ -249,4 +250,15 @@
         assertNotNull(ssl);
         assertTrue(SSLSocket.class.isAssignableFrom(ssl.getClass()));
     }
+
+
+    public void test_SSLSocketFactory_createSocket_withConsumedInputStream()
+            throws Exception {
+        try {
+            SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+            Socket sslSocket = sf.createSocket(null, (InputStream) null, false);
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
 }
diff --git a/luni/src/test/java/libcore/net/MimeUtilsTest.java b/luni/src/test/java/libcore/net/MimeUtilsTest.java
index ac0c017..af8f479 100644
--- a/luni/src/test/java/libcore/net/MimeUtilsTest.java
+++ b/luni/src/test/java/libcore/net/MimeUtilsTest.java
@@ -76,4 +76,13 @@
     assertEquals("video/3gpp2", MimeUtils.guessMimeTypeFromExtension("3gpp2"));
     assertEquals("video/3gpp2", MimeUtils.guessMimeTypeFromExtension("3g2"));
   }
+
+  public void test_37167977() {
+    // https://tools.ietf.org/html/rfc5334#section-10.1
+    assertEquals("audio/ogg", MimeUtils.guessMimeTypeFromExtension("ogg"));
+    assertEquals("audio/ogg", MimeUtils.guessMimeTypeFromExtension("oga"));
+    assertEquals("audio/ogg", MimeUtils.guessMimeTypeFromExtension("spx"));
+    assertEquals("video/ogg", MimeUtils.guessMimeTypeFromExtension("ogv"));
+  }
+
 }
diff --git a/luni/src/test/java/libcore/sun/net/util/IPAddressUtilTest.java b/luni/src/test/java/libcore/sun/net/util/IPAddressUtilTest.java
new file mode 100644
index 0000000..9294309
--- /dev/null
+++ b/luni/src/test/java/libcore/sun/net/util/IPAddressUtilTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.sun.net.util;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+import static sun.net.util.IPAddressUtil.textToNumericFormatV4;
+
+public class IPAddressUtilTest extends TestCase {
+
+    public void test_textToNumericFormatV4_valid() {
+        assertBytesEquals(0, 0, 0, 0, textToNumericFormatV4("0.0.0.0"));
+        assertBytesEquals(1, 2, 3, 4, textToNumericFormatV4("1.2.3.4"));
+        assertBytesEquals(255, 255, 255, 255, textToNumericFormatV4("255.255.255.255"));
+        assertBytesEquals(123, 23, 255, 37, textToNumericFormatV4("123.23.255.37"));
+        assertBytesEquals(192, 168, 0, 42, textToNumericFormatV4("192.168.0.42"));
+    }
+
+    public void test_textToNumericFormatV4_invalid() {
+        // Wrong number of components
+        assertNull(textToNumericFormatV4("1"));
+        assertNull(textToNumericFormatV4("1.2"));
+        assertNull(textToNumericFormatV4("1.2.3"));
+        assertNull(textToNumericFormatV4("1.2.3.4.5"));
+
+        // Extra dots in various places
+        assertNull(textToNumericFormatV4("1..3.4"));
+        assertNull(textToNumericFormatV4("1..2.3.4"));
+        assertNull(textToNumericFormatV4(".1.2.3"));
+        assertNull(textToNumericFormatV4(".1.2.3.4"));
+        assertNull(textToNumericFormatV4("1.2.3.4."));
+
+        // Out of bounds values
+        assertNull(textToNumericFormatV4("256.2.3.4"));
+        assertNull(textToNumericFormatV4("1.256.3.4"));
+        assertNull(textToNumericFormatV4("1.2.256.4"));
+        assertNull(textToNumericFormatV4("1.2.3.256"));
+        assertNull(textToNumericFormatV4("1.-2.3.4"));
+    }
+
+    private static void assertBytesEquals(int a, int b, int c, int d, byte[] actual) {
+        byte[] expected = new byte[] { (byte) a, (byte) b, (byte) c, (byte) d };
+        assertTrue("Expected " + Arrays.toString(expected) + ", got " + Arrays.toString(actual),
+                Arrays.equals(expected, actual));
+    }
+
+}
diff --git a/luni/src/test/java/libcore/sun/util/logging/PlatformLoggerTest.java b/luni/src/test/java/libcore/sun/util/logging/PlatformLoggerTest.java
new file mode 100644
index 0000000..d48d92a
--- /dev/null
+++ b/luni/src/test/java/libcore/sun/util/logging/PlatformLoggerTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.sun.util.logging;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.logging.Level;
+
+import sun.util.logging.PlatformLogger;
+
+public class PlatformLoggerTest extends TestCase {
+
+    /**
+     * Checks that the values of the private static final int constants in
+     * {@link PlatformLogger} code match the corresponding
+     * {@link Level#intValue()}. This constraint is mentioned in a comment
+     * in PlatformLogger.java.
+     */
+    public void testLogLevelConstants() throws Exception {
+        assertLogLevel("SEVERE", Level.SEVERE);
+        assertLogLevel("WARNING", Level.WARNING);
+        assertLogLevel("INFO", Level.INFO);
+        assertLogLevel("CONFIG", Level.CONFIG);
+        assertLogLevel("FINE", Level.FINE);
+        assertLogLevel("FINER", Level.FINER);
+        assertLogLevel("FINEST", Level.FINEST);
+        assertLogLevel("ALL", Level.ALL);
+        assertLogLevel("OFF", Level.OFF);
+    }
+
+    private void assertLogLevel(String levelName, Level javaUtilLoggingLevel) throws Exception {
+        Field field =  PlatformLogger.class.getDeclaredField(levelName);
+        field.setAccessible(true);
+        int platformLoggerValue = field.getInt(PlatformLogger.class);
+        int javaUtilLoggingValue = javaUtilLoggingLevel.intValue();
+        assertEquals(levelName, javaUtilLoggingValue, platformLoggerValue);
+
+        // Check that the field is a constant (static and final); we don't care about
+        // other modifiers (public/private).
+        int requiredModifiers = Modifier.STATIC | Modifier.FINAL;
+        assertEquals(requiredModifiers, field.getModifiers() & requiredModifiers);
+    }
+
+}
diff --git a/ojluni/src/main/java/java/awt/font/TextAttribute.java b/ojluni/src/main/java/java/awt/font/TextAttribute.java
index 04a921d..7dff4ad 100644
--- a/ojluni/src/main/java/java/awt/font/TextAttribute.java
+++ b/ojluni/src/main/java/java/awt/font/TextAttribute.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,8 @@
 import java.util.Map;
 import java.util.HashMap;
 
+// Android-removed: List of classes for use with attribute keys; Android doesn't have those.
+// Android-removed: "Summary of attributes" section. Android doesn't have the referenced classes.
 /**
  * The <code>TextAttribute</code> class defines attribute keys and
  * attribute values used for text rendering.
@@ -62,7 +64,7 @@
  *   <LI>a description of the effect.
  * </UL>
  * <p>
- * <H4>Values</H4>
+ * <H3>Values</H3>
  * <UL>
  *   <LI>The values of attributes must always be immutable.
  *   <LI>Where value limitations are given, any value outside of that
@@ -90,178 +92,12 @@
  *
  * </UL>
  *
- * @see java.text.AttributedCharacterIterator
  */
-
-// Android-removed: Removed Summary of Attributes.
-/* <h4>Summary of attributes</h4>
- * <p>
- * <font size="-1">
- * <table align="center" border="0" cellspacing="0" cellpadding="2" width="%95"
- *     summary="Key, value type, principal constants, and default value
- *     behavior of all TextAttributes">
- * <tr bgcolor="#ccccff">
- * <th valign="TOP" align="CENTER">Key</th>
- * <th valign="TOP" align="CENTER">Value Type</th>
- * <th valign="TOP" align="CENTER">Principal Constants</th>
- * <th valign="TOP" align="CENTER">Default Value</th>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #FAMILY}</td>
- * <td valign="TOP">String</td>
- * <td valign="TOP">See Font {@link java.awt.Font#DIALOG DIALOG},
-{@link java.awt.Font#DIALOG_INPUT DIALOG_INPUT},<br> {@link java.awt.Font#SERIF SERIF},
-{@link java.awt.Font#SANS_SERIF SANS_SERIF}, and {@link java.awt.Font#MONOSPACED MONOSPACED}.
-</td>
- * <td valign="TOP">"Default" (use platform default)</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #WEIGHT}</td>
- * <td valign="TOP">Number</td>
- * <td valign="TOP">WEIGHT_REGULAR, WEIGHT_BOLD</td>
- * <td valign="TOP">WEIGHT_REGULAR</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #WIDTH}</td>
- * <td valign="TOP">Number</td>
- * <td valign="TOP">WIDTH_CONDENSED, WIDTH_REGULAR,<br>WIDTH_EXTENDED</td>
- * <td valign="TOP">WIDTH_REGULAR</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #POSTURE}</td>
- * <td valign="TOP">Number</td>
- * <td valign="TOP">POSTURE_REGULAR, POSTURE_OBLIQUE</td>
- * <td valign="TOP">POSTURE_REGULAR</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #SIZE}</td>
- * <td valign="TOP">Number</td>
- * <td valign="TOP">none</td>
- * <td valign="TOP">12.0</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #TRANSFORM}</td>
- * <td valign="TOP">{@link TransformAttribute}</td>
- * <td valign="TOP">See TransformAttribute {@link TransformAttribute#IDENTITY IDENTITY}</td>
- * <td valign="TOP">TransformAttribute.IDENTITY</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #SUPERSCRIPT}</td>
- * <td valign="TOP">Integer</td>
- * <td valign="TOP">SUPERSCRIPT_SUPER, SUPERSCRIPT_SUB</td>
- * <td valign="TOP">0 (use the standard glyphs and metrics)</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #FONT}</td>
- * <td valign="TOP">{@link java.awt.Font}</td>
- * <td valign="TOP">none</td>
- * <td valign="TOP">null (do not override font resolution)</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #CHAR_REPLACEMENT}</td>
- * <td valign="TOP">{@link GraphicAttribute}</td>
- * <td valign="TOP">none</td>
- * <td valign="TOP">null (draw text using font glyphs)</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #FOREGROUND}</td>
- * <td valign="TOP">{@link java.awt.Paint}</td>
- * <td valign="TOP">none</td>
- * <td valign="TOP">null (use current graphics paint)</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #BACKGROUND}</td>
- * <td valign="TOP">{@link java.awt.Paint}</td>
- * <td valign="TOP">none</td>
- * <td valign="TOP">null (do not render background)</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #UNDERLINE}</td>
- * <td valign="TOP">Integer</td>
- * <td valign="TOP">UNDERLINE_ON</td>
- * <td valign="TOP">-1 (do not render underline)</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #STRIKETHROUGH}</td>
- * <td valign="TOP">Boolean</td>
- * <td valign="TOP">STRIKETHROUGH_ON</td>
- * <td valign="TOP">false (do not render strikethrough)</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #RUN_DIRECTION}</td>
- * <td valign="TOP">Boolean</td>
- * <td valign="TOP">RUN_DIRECTION_LTR<br>RUN_DIRECTION_RTL</td>
- * <td valign="TOP">null (use {@link java.text.Bidi} standard default)</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #BIDI_EMBEDDING}</td>
- * <td valign="TOP">Integer</td>
- * <td valign="TOP">none</td>
- * <td valign="TOP">0 (use base line direction)</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #JUSTIFICATION}</td>
- * <td valign="TOP">Number</td>
- * <td valign="TOP">JUSTIFICATION_FULL</td>
- * <td valign="TOP">JUSTIFICATION_FULL</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #INPUT_METHOD_HIGHLIGHT}</td>
- * <td valign="TOP">{@link java.awt.im.InputMethodHighlight},<br>{@link java.text.Annotation}</td>
- * <td valign="TOP">(see class)</td>
- * <td valign="TOP">null (do not apply input highlighting)</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #INPUT_METHOD_UNDERLINE}</td>
- * <td valign="TOP">Integer</td>
- * <td valign="TOP">UNDERLINE_LOW_ONE_PIXEL,<br>UNDERLINE_LOW_TWO_PIXEL</td>
- * <td valign="TOP">-1 (do not render underline)</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #SWAP_COLORS}</td>
- * <td valign="TOP">Boolean</td>
- * <td valign="TOP">SWAP_COLORS_ON</td>
- * <td valign="TOP">false (do not swap colors)</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #NUMERIC_SHAPING}</td>
- * <td valign="TOP">{@link java.awt.font.NumericShaper}</td>
- * <td valign="TOP">none</td>
- * <td valign="TOP">null (do not shape digits)</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #KERNING}</td>
- * <td valign="TOP">Integer</td>
- * <td valign="TOP">KERNING_ON</td>
- * <td valign="TOP">0 (do not request kerning)</td>
- * </tr>
- * <tr bgcolor="#eeeeff">
- * <td valign="TOP">{@link #LIGATURES}</td>
- * <td valign="TOP">Integer</td>
- * <td valign="TOP">LIGATURES_ON</td>
- * <td valign="TOP">0 (do not form optional ligatures)</td>
- * </tr>
- * <tr>
- * <td valign="TOP">{@link #TRACKING}</td>
- * <td valign="TOP">Number</td>
- * <td valign="TOP">TRACKING_LOOSE, TRACKING_TIGHT</td>
- * <td valign="TOP">0 (do not add tracking)</td>
- * </tr>
- * </table>
- * </font>
- *
- * @see java.awt.Font
- * @see java.awt.font.TextLayout
- */
-// Android-removed
-//
-// {@link java.awt.Font Font},
-// {@link java.awt.font.TextLayout TextLayout},
-// {@link java.text.AttributedCharacterIterator AttributedCharacterIterator},
 public final class TextAttribute extends Attribute {
 
     // table of all instances in this class, used by readResolve
-    private static final Map instanceMap = new HashMap(29);
+    private static final Map<String, TextAttribute>
+            instanceMap = new HashMap<String, TextAttribute>(29);
 
     /**
      * Constructs a <code>TextAttribute</code> with the specified name.
@@ -284,7 +120,7 @@
                 "subclass didn't correctly implement readResolve");
         }
 
-        TextAttribute instance = (TextAttribute) instanceMap.get(getName());
+        TextAttribute instance = instanceMap.get(getName());
         if (instance != null) {
             return instance;
         } else {
@@ -302,6 +138,7 @@
     // For use with Font.
     //
 
+    // Android-removed: Don't link to java.awt.Font class, it doesn't exist on Android.
     /**
      * Attribute key for the font name.  Values are instances of
      * <b><code>String</code></b>.  The default value is
@@ -324,13 +161,6 @@
      * The "Bold" in the name is part of the face name, not a separate
      * request that the font's weight be bold.</p>
      */
-    // Android-removed links to font names.
-    //
-    // {@link java.awt.Font#DIALOG DIALOG},
-    // {@link java.awt.Font#DIALOG_INPUT DIALOG_INPUT},
-    // {@link java.awt.Font#SANS_SERIF SANS_SERIF},
-    // {@link java.awt.Font#SERIF SERIF}, and
-    // {@link java.awt.Font#MONOSPACED MONOSPACED}.
     public static final TextAttribute FAMILY =
         new TextAttribute("family");
 
@@ -490,6 +320,7 @@
     public static final Float WIDTH_EXTENDED =
         Float.valueOf(1.5f);
 
+    // Android-removed: Don't link to java.awt.Font class, it doesn't exist on Android.
     /**
      * Attribute key for the posture of a font.  Values are instances
      * of <b><code>Number</code></b>. The default value is
@@ -510,8 +341,6 @@
      * <code>Font.getItalicAngle</code>.
      *
      */
-    // Android-removed.
-    // @see java.awt.Font#getItalicAngle()
     public static final TextAttribute POSTURE =
         new TextAttribute("posture");
 
@@ -548,6 +377,8 @@
     public static final TextAttribute SIZE =
         new TextAttribute("size");
 
+    // Android-removed: References to classes that don't exist on Android.
+    // These classes were AffineTransform, Font, and TransformAttribute.
     /**
      * Attribute key for the transform of a font.  Values are
      * instances of <b><code>TransformAttribute</code></b>.  The
@@ -566,23 +397,6 @@
      * with a rotated TRANSFORM and an unrotated TRANSFORM will measure as
      * having the same ascent, descent, and advance.</p>
      */
-     // Android-removed
-     //
-     // <p>This corresponds to the transform passed to
-     // <code>Font.deriveFont(AffineTransform)</code>.  Since that
-     // transform is mutable and <code>TextAttribute</code> values must
-     // not be, the <code>TransformAttribute</code> wrapper class is
-     // used.
-     //
-     // <p>The <code>TransformAttribute</code> class defines the
-     // constant {@link TransformAttribute#IDENTITY IDENTITY}.
-     // @see TransformAttribute
-     // @see java.awt.geom.AffineTransform
-     //
-     // <p>In styled text, the baselines for each such run are aligned
-     // one after the other to potentially create a non-linear baseline
-     // for the entire run of text. For more information, see {@link
-     // TextLayout#getLayoutPath}.</p>
      public static final TextAttribute TRANSFORM =
         new TextAttribute("transform");
 
@@ -621,6 +435,7 @@
     public static final Integer SUPERSCRIPT_SUB =
         Integer.valueOf(-1);
 
+    // Android-removed: Don't link to java.awt.Font class, it doesn't exist on Android.
     /**
      * Attribute key used to provide the font to use to render text.
      *
@@ -673,17 +488,6 @@
      * <code>Font</code> but can be overridden by other values in the
      * <code>Map</code>.
      */
-    // Android-removed
-    // Values are instances of {@link java.awt.Font}.
-    //
-    // <p><em>Note:</em><code>Font's</code> <code>Map</code>-based
-    // constructor and <code>deriveFont</code> methods do not process
-    // the <code>FONT</code> attribute, as these are used to create
-    // new <code>Font</code> objects.  Instead, {@link
-    // java.awt.Font#getFont(Map) Font.getFont(Map)} should be used to
-    // handle the <code>FONT</code> attribute.
-    //
-    // @see java.awt.Font
     public static final TextAttribute FONT =
         new TextAttribute("font");
 
@@ -900,6 +704,7 @@
     // For use by input method.
     //
 
+    // Android-removed: References to java.awt.im.InputMethodHighlight (doesn't exist on Android).
     /**
      * Attribute key for input method highlight styles.
      *
@@ -909,24 +714,6 @@
      *
      * @see java.text.Annotation
      */
-    // Android-removed
-    //
-    // <p>Values are instances of {@link
-    // java.awt.im.InputMethodHighlight} or {@link
-    // java.text.Annotation}.
-    // 
-    // <p>If adjacent runs of text with the same
-    // <code>InputMethodHighlight</code> need to be rendered
-    // separately, the <code>InputMethodHighlights</code> should be
-    // wrapped in <code>Annotation</code> instances.
-    //
-    // <p>Input method highlights are used while text is being
-    // composed by an input method. Text editing components should
-    // retain them even if they generally only deal with unstyled
-    // text, and make them available to the drawing routines.
-    //
-    // @see java.awt.Font
-    // @see java.awt.im.InputMethodHighlight
     public static final TextAttribute INPUT_METHOD_HIGHLIGHT =
         new TextAttribute("input method highlight");
 
diff --git a/ojluni/src/main/java/java/io/Console.java b/ojluni/src/main/java/java/io/Console.java
index 2b4e4e6..b25759c 100644
--- a/ojluni/src/main/java/java/io/Console.java
+++ b/ojluni/src/main/java/java/io/Console.java
@@ -514,11 +514,10 @@
         }
     }
 
-    // Android-changed: Remove SharedSecrets setup and also the shutdown
-    // hook that's a no-op (but causes trouble when it's turned on).
+    // Android-removed: SharedSecrets setup and also the shutdown hook.
+    // The hook is a no-op (but causes trouble when it's turned on).
 
-    private static Console cons;
-
+    // Android-changed: Use @hide rather than sun.misc.SharedSecrets to expose console().
     /** @hide */
     public static Console console() {
         if (istty()) {
@@ -528,15 +527,16 @@
         }
         return null;
     }
-
+    private static Console cons;
     private native static boolean istty();
-
     private Console() {
+    // BEGIN Android-changed: Support custom in/out streams for testing.
       this(new FileInputStream(FileDescriptor.in), new FileOutputStream(FileDescriptor.out));
     }
 
     // Constructor for tests
     private Console(InputStream inStream, OutputStream outStream) {
+    // END Android-changed: Support custom in/out streams for testing.
         readLock = new Object();
         writeLock = new Object();
         String csname = encoding();
diff --git a/ojluni/src/main/java/java/io/DeleteOnExitHook.java b/ojluni/src/main/java/java/io/DeleteOnExitHook.java
index 447f038..e988f9b 100644
--- a/ojluni/src/main/java/java/io/DeleteOnExitHook.java
+++ b/ojluni/src/main/java/java/io/DeleteOnExitHook.java
@@ -36,11 +36,13 @@
 class DeleteOnExitHook {
     private static LinkedHashSet<String> files = new LinkedHashSet<>();
     static {
+        // BEGIN Android-changed: Use Runtime.addShutdownHook() rather than SharedSecrets.
         Runtime.getRuntime().addShutdownHook(new Thread() {
             public void run() {
                 runHooks();
             }
         });
+        // END Android-changed: Use Runtime.addShutdownHook() rather than SharedSecrets.
     }
 
     private DeleteOnExitHook() {}
diff --git a/ojluni/src/main/java/java/io/ExpiringCache.java b/ojluni/src/main/java/java/io/ExpiringCache.java
index 02fd222..d0edb11 100644
--- a/ojluni/src/main/java/java/io/ExpiringCache.java
+++ b/ojluni/src/main/java/java/io/ExpiringCache.java
@@ -65,8 +65,12 @@
     ExpiringCache(long millisUntilExpiration) {
         this.millisUntilExpiration = millisUntilExpiration;
         map = new LinkedHashMap<String,Entry>() {
-            @Override
-            protected boolean removeEldestEntry(Map.Entry eldest) {
+            // Android-changed: Qualified ExpiringCache.Entry to distinguish from Map.Entry.
+            // There seems to be a compiler difference between javac and jack here;
+            // Map.Entry<String,Entry> doesn't work on jack since the latter "Entry" gets
+            // interpreted as referring to Map.Entry rather than ExpiringCache.Entry.
+            // protected boolean removeEldestEntry(Map.Entry<String,Entry> eldest) {
+            protected boolean removeEldestEntry(Map.Entry<String,ExpiringCache.Entry> eldest) {
               return size() > MAX_ENTRIES;
             }
           };
diff --git a/ojluni/src/main/java/java/io/FileDescriptor.java b/ojluni/src/main/java/java/io/FileDescriptor.java
index 7c82505..75f7388 100644
--- a/ojluni/src/main/java/java/io/FileDescriptor.java
+++ b/ojluni/src/main/java/java/io/FileDescriptor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,17 +50,19 @@
 // the file descriptor.
 public final class FileDescriptor {
 
+    // Android-changed: Renamed fd to descriptor to avoid issues with JNI/reflection
+    // fetching the descriptor value.
     private int descriptor;
 
     /**
      * Constructs an (invalid) FileDescriptor
      * object.
      */
-    public FileDescriptor() {
+    public /* */ FileDescriptor() {
         descriptor = -1;
     }
 
-    private FileDescriptor(int descriptor) {
+    private /* */ FileDescriptor(int descriptor) {
         this.descriptor = descriptor;
     }
 
@@ -71,6 +73,7 @@
      *
      * @see     java.lang.System#in
      */
+    // Android-changed: Duplicates of FDs needed for RuntimeInit#redirectLogStreams
     public static final FileDescriptor in = dupFd(0);
 
     /**
@@ -79,6 +82,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);
 
     /**
@@ -88,6 +92,7 @@
      *
      * @see     java.lang.System#err
      */
+    // Android-changed: Duplicates of FDs needed for RuntimeInit#redirectLogStreams
     public static final FileDescriptor err = dupFd(2);
 
     /**
@@ -131,12 +136,16 @@
      */
     public native void sync() throws SyncFailedException;
 
+    // Android-removed: initIDs not used to allow compile-time intialization
+    /* This routine initializes JNI field offsets for the class */
+    //private static native void initIDs();
+
     /**
      * 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.
      * @hide internal use only
      */
-    // Android-added.
+    // Android-added: Needed for framework to access descriptor value
     public final int getInt$() {
         return descriptor;
     }
@@ -146,7 +155,7 @@
      * your needs with a libcore maintainer before using this method.
      * @hide internal use only
      */
-    // Android-added.
+    // Android-added: Needed for framework to access descriptor value
     public final void setInt$(int fd) {
         this.descriptor = fd;
     }
@@ -154,12 +163,12 @@
     /**
      * @hide internal use only
      */
-    // Android-added.
+    // Android-added: Needed for framework to test if it's a socket
     public boolean isSocket$() {
         return isSocket(descriptor);
     }
 
-    // Android-added.
+    // 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));
@@ -172,25 +181,24 @@
     // Set up JavaIOFileDescriptorAccess in SharedSecrets
     static {
         sun.misc.SharedSecrets.setJavaIOFileDescriptorAccess(
-                new sun.misc.JavaIOFileDescriptorAccess() {
-                    public void set(FileDescriptor obj, int fd) {
-                        obj.descriptor = fd;
-                    }
-
-                    public int get(FileDescriptor obj) {
-                        return obj.descriptor;
-                    }
-
-                    public void setHandle(FileDescriptor obj, long handle) {
-                        throw new UnsupportedOperationException();
-                    }
-
-                    public long getHandle(FileDescriptor obj) {
-                        throw new UnsupportedOperationException();
-                    }
+            new sun.misc.JavaIOFileDescriptorAccess() {
+                public void set(FileDescriptor obj, int fd) {
+                    obj.descriptor = fd;
                 }
+
+                public int get(FileDescriptor obj) {
+                    return obj.descriptor;
+                }
+
+                public void setHandle(FileDescriptor obj, long handle) {
+                    throw new UnsupportedOperationException();
+                }
+
+                public long getHandle(FileDescriptor obj) {
+                    throw new UnsupportedOperationException();
+                }
+            }
         );
     }
-
-
+// Android-removed: Removed method required for parents reference counting
 }
diff --git a/ojluni/src/main/java/java/io/FilePermission.java b/ojluni/src/main/java/java/io/FilePermission.java
index 814a695..f9544c7 100644
--- a/ojluni/src/main/java/java/io/FilePermission.java
+++ b/ojluni/src/main/java/java/io/FilePermission.java
@@ -27,6 +27,8 @@
 
 import java.security.*;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/io/InterruptedIOException.java b/ojluni/src/main/java/java/io/InterruptedIOException.java
index e4ed419..25569dd 100644
--- a/ojluni/src/main/java/java/io/InterruptedIOException.java
+++ b/ojluni/src/main/java/java/io/InterruptedIOException.java
@@ -74,7 +74,7 @@
     public int bytesTransferred = 0;
 
     /** @hide */
-    // Android-added.
+    // Android-added: Additional constructor for internal use.
     public InterruptedIOException(Throwable cause) {
         super(cause);
     }
@@ -84,7 +84,7 @@
      *
      * @hide internal use only
      */
-    // Android-added.
+    // Android-added: Additional constructor for internal use.
     public InterruptedIOException(String detailMessage, Throwable cause) {
         super(detailMessage, cause);
     }
diff --git a/ojluni/src/main/java/java/io/PrintStream.java b/ojluni/src/main/java/java/io/PrintStream.java
index 08bb3a3..809d39b 100644
--- a/ojluni/src/main/java/java/io/PrintStream.java
+++ b/ojluni/src/main/java/java/io/PrintStream.java
@@ -70,6 +70,7 @@
     private BufferedWriter textOut;
     private OutputStreamWriter charOut;
 
+    // Android-added: Lazy initialization of charOut and textOut.
     private Charset charset;
 
     /**
@@ -104,11 +105,18 @@
     private PrintStream(boolean autoFlush, OutputStream out) {
         super(out);
         this.autoFlush = autoFlush;
+        // Android-changed: Lazy initialization of charOut and textOut.
+        // this.charOut = new OutputStreamWriter(this);
+        // this.textOut = new BufferedWriter(charOut);
     }
 
     private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
         super(out);
         this.autoFlush = autoFlush;
+        // Android-changed: Lazy initialization of charOut and textOut.
+        // this.charOut = new OutputStreamWriter(this, charset);
+        // this.textOut = new BufferedWriter(charOut);
+        this.charset = charset;
     }
 
     /* Variant of the private constructor so that the given charset name
@@ -344,7 +352,7 @@
 
     private boolean closing = false; /* To avoid recursive closing */
 
-    // Android-changed: Lazily initialize textOut.
+    // BEGIN Android-added: Lazy initialization of charOut and textOut.
     private BufferedWriter getTextOut() {
         if (textOut == null) {
             charOut = charset != null ? new OutputStreamWriter(this, charset) :
@@ -353,6 +361,7 @@
         }
         return textOut;
     }
+    // END Android-added: Lazy initialization of charOut and textOut.
 
     /**
      * Closes the stream.  This is done by flushing the stream and then closing
@@ -365,10 +374,12 @@
             if (! closing) {
                 closing = true;
                 try {
-                    // Android-changed: Lazily initialized.
+                    // BEGIN Android-changed: Lazy initialization of charOut and textOut.
+                    // textOut.close();
                     if (textOut != null) {
                         textOut.close();
                     }
+                    // END Android-changed: Lazy initialization of charOut and textOut.
                     out.close();
                 }
                 catch (IOException x) {
@@ -512,7 +523,7 @@
         try {
             synchronized (this) {
                 ensureOpen();
-                // Android-changed: Lazily initialized.
+                // Android-added: Lazy initialization of charOut and textOut.
                 BufferedWriter textOut = getTextOut();
                 textOut.write(buf);
                 textOut.flushBuffer();
@@ -536,7 +547,7 @@
         try {
             synchronized (this) {
                 ensureOpen();
-                // Android-changed: Lazily initialized.
+                // Android-added: Lazy initialization of charOut and textOut.
                 BufferedWriter textOut = getTextOut();
                 textOut.write(s);
                 textOut.flushBuffer();
@@ -557,7 +568,7 @@
         try {
             synchronized (this) {
                 ensureOpen();
-                // Android-changed: Lazily initialized.
+                // Android-added: Lazy initialization of charOut and textOut.
                 BufferedWriter textOut = getTextOut();
                 textOut.newLine();
                 textOut.flushBuffer();
diff --git a/ojluni/src/main/java/java/io/RandomAccessFile.java b/ojluni/src/main/java/java/io/RandomAccessFile.java
index 34eb7ab..f4830c1 100755
--- a/ojluni/src/main/java/java/io/RandomAccessFile.java
+++ b/ojluni/src/main/java/java/io/RandomAccessFile.java
@@ -65,10 +65,12 @@
 
 public class RandomAccessFile implements DataOutput, DataInput, Closeable {
 
+    // BEGIN Android-added: CloseGuard and some helper fields for Android changes in this file.
     private final CloseGuard guard = CloseGuard.get();
     private final byte[] scratch = new byte[8];
     private boolean syncMetadata = false;
     private int mode;
+    // END Android-added: CloseGuard and some helper fields for Android changes in this file.
 
     private FileDescriptor fd;
     private FileChannel channel = null;
@@ -82,11 +84,14 @@
 
     private Object closeLock = new Object();
     private volatile boolean closed = false;
+
+    // BEGIN Android-added: IoTracker.
     /**
      * A single tracker to track both read and write. The tracker resets when the operation
      * performed is different from the operation last performed.
      */
     private final IoTracker ioTracker = new IoTracker();
+    // END Android-added: IoTracker.
 
     /**
      * Creates a random access file stream to read from, and optionally
@@ -216,43 +221,57 @@
         throws FileNotFoundException
     {
         String name = (file != null ? file.getPath() : null);
-        this.mode = -1;
+        int imode = -1;
         if (mode.equals("r")) {
-            this.mode = O_RDONLY;
+            imode = O_RDONLY;
         } else if (mode.startsWith("rw")) {
             // Android-changed: Added. O_CREAT
-            this.mode = O_RDWR | O_CREAT;
+            // imode = O_RDWR;
+            imode = O_RDWR | O_CREAT;
             rw = true;
             if (mode.length() > 2) {
                 if (mode.equals("rws")) {
+                    // Android-changed: Don't use O_SYNC for "rws". Is this correct?
+                    // imode |= O_SYNC;
                     syncMetadata = true;
                 } else if (mode.equals("rwd")) {
-                    // Android-changed: Should this be O_DSYNC and the above O_SYNC ?
-                    this.mode |= O_SYNC;
+                    // Android-changed: Use O_SYNC rather than O_DSYNC for "rwd". Is this correct?
+                    // imode |= O_DSYNC;
+                    imode |= O_SYNC;
                 } else {
-                    this.mode = -1;
+                    imode = -1;
                 }
             }
         }
-
-        if (this.mode < 0) {
+        if (imode < 0) {
             throw new IllegalArgumentException("Illegal mode \"" + mode
                                                + "\" must be one of "
                                                + "\"r\", \"rw\", \"rws\","
                                                + " or \"rwd\"");
         }
-
+        // Android-removed: do not use legacy security code
+        /*
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(name);
+            if (rw) {
+                security.checkWrite(name);
+            }
+        }
+        */
         if (name == null) {
+            // Android-changed: different exception message in ctor when file == null.
+            // throw new NullPointerException();
             throw new NullPointerException("file == null");
         }
-
         if (file.isInvalid()) {
             throw new FileNotFoundException("Invalid file path");
         }
         this.path = name;
+        this.mode = imode;
 
-        // Android-changed: Use IoBridge.open() instead of open.
-        fd = IoBridge.open(file.getPath(), this.mode);
+        // BEGIN Android-changed: Use IoBridge.open() instead of open.
+        fd = IoBridge.open(name, imode);
         if (syncMetadata) {
             try {
                 fd.sync();
@@ -261,6 +280,7 @@
             }
         }
         guard.open("close");
+        // END Android-changed: Use IoBridge.open() instead of open.
     }
 
     /**
@@ -321,6 +341,8 @@
      *                          end-of-file has been reached.
      */
     public int read() throws IOException {
+        // Android-changed: Implement on top of low-level API, not directly natively.
+        // return read0();
         return (read(scratch, 0, 1) != -1) ? scratch[0] & 0xff : -1;
     }
 
@@ -332,6 +354,7 @@
      * @exception IOException If an I/O error has occurred.
      */
     private int readBytes(byte b[], int off, int len) throws IOException {
+        // Android-changed: Implement on top of low-level API, not directly natively.
         ioTracker.trackIo(len, IoTracker.Mode.READ);
         return IoBridge.read(fd, b, off, len);
     }
@@ -474,6 +497,8 @@
      * @exception  IOException  if an I/O error occurs.
      */
     public void write(int b) throws IOException {
+        // Android-changed: Implement on top of low-level API, not directly natively.
+        // write0(b);
         scratch[0] = (byte) (b & 0xff);
         write(scratch, 0, 1);
     }
@@ -481,11 +506,13 @@
     /**
      * Writes a sub array as a sequence of bytes.
      * @param b the data to be written
+
      * @param off the start offset in the data
      * @param len the number of bytes that are written
      * @exception IOException If an I/O error has occurred.
      */
     private void writeBytes(byte b[], int off, int len) throws IOException {
+        // Android-changed: Implement on top of low-level API, not directly natively.
         ioTracker.trackIo(len, IoTracker.Mode.WRITE);
         IoBridge.write(fd, b, off, len);
         // if we are in "rws" mode, attempt to sync file+metadata
@@ -528,6 +555,7 @@
      * @exception  IOException  if an I/O error occurs.
      */
     public long getFilePointer() throws IOException {
+        // Android-changed: Implement on top of low-level API, not directly natively.
         try {
             return Libcore.os.lseek(fd, 0L, SEEK_CUR);
         } catch (ErrnoException errnoException) {
@@ -543,21 +571,26 @@
      * change only by writing after the offset has been set beyond the end
      * of the file.
      *
-     * @param      offset   the offset position, measured in bytes from the
+     * @param      pos   the offset position, measured in bytes from the
      *                   beginning of the file, at which to set the file
      *                   pointer.
      * @exception  IOException  if {@code pos} is less than
      *                          {@code 0} or if an I/O error occurs.
      */
-    public void seek(long offset) throws IOException {
-        if (offset < 0) {
-            throw new IOException("offset < 0: " + offset);
-        }
-        try {
-            Libcore.os.lseek(fd, offset, SEEK_SET);
-            ioTracker.reset();
-        } catch (ErrnoException errnoException) {
-            throw errnoException.rethrowAsIOException();
+    public void seek(long pos) throws IOException {
+        if (pos < 0) {
+            // Android-changed: different exception message for seek(-1).
+            // throw new IOException("Negative seek offset");
+            throw new IOException("offset < 0: " + pos);
+        } else {
+            // Android-changed: Implement on top of low-level API, not directly natively.
+            // seek0(pos);
+            try {
+                Libcore.os.lseek(fd, pos, SEEK_SET);
+                ioTracker.reset();
+            } catch (ErrnoException errnoException) {
+                throw errnoException.rethrowAsIOException();
+            }
         }
     }
 
@@ -568,6 +601,7 @@
      * @exception  IOException  if an I/O error occurs.
      */
     public long length() throws IOException {
+        // Android-changed: Implement on top of low-level API, not directly natively.
         try {
             return Libcore.os.fstat(fd).st_size;
         } catch (ErrnoException errnoException) {
@@ -595,6 +629,7 @@
      * @since      1.2
      */
     public void setLength(long newLength) throws IOException {
+        // BEGIN Android-changed: Implement on top of low-level API, not directly natively.
         if (newLength < 0) {
             throw new IllegalArgumentException("newLength < 0");
         }
@@ -612,6 +647,7 @@
         if (syncMetadata) {
             fd.sync();
         }
+        // END Android-changed: Implement on top of low-level API, not directly natively.
     }
 
 
@@ -638,10 +674,12 @@
             closed = true;
         }
 
+        // BEGIN Android-changed: Implement on top of low-level API, not directly natively.
         if (channel != null && channel.isOpen()) {
             channel.close();
         }
         IoBridge.closeAndSignalBlockedThreads(fd);
+        // END Android-changed: Implement on top of low-level API, not directly natively.
     }
 
     //
@@ -1166,6 +1204,7 @@
         DataOutputStream.writeUTF(str, this);
     }
 
+    // Android-added: use finalize() to detect if not close()d.
     @Override protected void finalize() throws Throwable {
         try {
             if (guard != null) {
diff --git a/ojluni/src/main/java/java/io/Serializable.java b/ojluni/src/main/java/java/io/Serializable.java
index 96ea33c..496aef7 100644
--- a/ojluni/src/main/java/java/io/Serializable.java
+++ b/ojluni/src/main/java/java/io/Serializable.java
@@ -25,6 +25,7 @@
 
 package java.io;
 
+// Android-added: Notes about serialVersionUID, using serialization judiciously, JSON.
 /**
  * Serializability of a class is enabled by the class implementing the
  * java.io.Serializable interface. Classes that do not implement this
diff --git a/ojluni/src/main/java/java/io/SerializablePermission.java b/ojluni/src/main/java/java/io/SerializablePermission.java
index e11f3ee..93bb4aa 100644
--- a/ojluni/src/main/java/java/io/SerializablePermission.java
+++ b/ojluni/src/main/java/java/io/SerializablePermission.java
@@ -27,8 +27,9 @@
 
 import java.security.*;
 
+// Android-changed: Replaced with empty implementation and documented as legacy security code.
 /**
- * Legacy security code; do not use.
+ * This legacy security is not supported on Android. Do not use.
  */
 public final class SerializablePermission extends BasicPermission {
 
diff --git a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
index c67a0a4..cc24e96 100644
--- a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -153,7 +153,7 @@
             newCapacity = minCapacity;
         }
         return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
-           ? hugeCapacity(minCapacity)
+            ? hugeCapacity(minCapacity)
             : newCapacity;
     }
 
diff --git a/ojluni/src/main/java/java/lang/ArrayIndexOutOfBoundsException.java b/ojluni/src/main/java/java/lang/ArrayIndexOutOfBoundsException.java
index 756c684..9c85456 100644
--- a/ojluni/src/main/java/java/lang/ArrayIndexOutOfBoundsException.java
+++ b/ojluni/src/main/java/java/lang/ArrayIndexOutOfBoundsException.java
@@ -66,16 +66,16 @@
         super(s);
     }
 
+    // Android-added: Additional constructor for internal use.
     /**
-     * Used internally for consistent high-quality error reporting.
      * @hide
      */
     public ArrayIndexOutOfBoundsException(int sourceLength, int index) {
         super("length=" + sourceLength + "; index=" + index);
     }
 
+    // Android-added: Additional constructor for internal use.
     /**
-     * Used internally for consistent high-quality error reporting.
      * @hide
      */
     public ArrayIndexOutOfBoundsException(int sourceLength, int offset,
diff --git a/ojluni/src/main/java/java/lang/Byte.java b/ojluni/src/main/java/java/lang/Byte.java
index ba2f588..d0031d0 100644
--- a/ojluni/src/main/java/java/lang/Byte.java
+++ b/ojluni/src/main/java/java/lang/Byte.java
@@ -518,7 +518,7 @@
     /** use serialVersionUID from JDK 1.1. for interoperability */
     private static final long serialVersionUID = -7183698231559129828L;
 
-    // BEGIN Android-changed
+    // BEGIN Android-added: toHexString() for internal use.
     /**
      * @hide
      */
@@ -542,5 +542,5 @@
         'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
         'U', 'V', 'W', 'X', 'Y', 'Z'
     };
-    // END Android-changed
+    // END Android-added: toHexString() for internal use.
 }
diff --git a/ojluni/src/main/java/java/lang/Class.java b/ojluni/src/main/java/java/lang/Class.java
index 3717cd7..ed9f915 100644
--- a/ojluni/src/main/java/java/lang/Class.java
+++ b/ojluni/src/main/java/java/lang/Class.java
@@ -2403,13 +2403,15 @@
         return (values != null) ? values.clone() : null;
     }
 
+    // Android-changed: Made public/hidden instead of using sun.misc.SharedSecrets.
     /**
      * Returns the elements of this enum class or null if this
      * Class object does not represent an enum type;
      * identical to getEnumConstants except that the result is
      * uncloned, cached, and shared by all callers.
+     * @hide
      */
-    T[] getEnumConstantsShared() {
+    public T[] getEnumConstantsShared() {
         if (!isEnum()) return null;
         return (T[]) Enum.getSharedConstants((Class) this);
     }
diff --git a/ojluni/src/main/java/java/lang/JavaLangAccess.java b/ojluni/src/main/java/java/lang/JavaLangAccess.java
deleted file mode 100644
index 2779c60..0000000
--- a/ojluni/src/main/java/java/lang/JavaLangAccess.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.lang;
-
-/**
- * @hide
- */
-public final class JavaLangAccess {
-  private JavaLangAccess() {
-  }
-
-  /**
-   * @hide
-   */
-  public static <E extends Enum<E>>
-          E[] getEnumConstantsShared(Class<E> klass) {
-      return klass.getEnumConstantsShared();
-  }
-}
diff --git a/ojluni/src/main/java/java/lang/RuntimePermission.java b/ojluni/src/main/java/java/lang/RuntimePermission.java
index 19dff55..2d05ba1 100644
--- a/ojluni/src/main/java/java/lang/RuntimePermission.java
+++ b/ojluni/src/main/java/java/lang/RuntimePermission.java
@@ -27,6 +27,8 @@
 
 import java.security.*;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/lang/SecurityManager.java b/ojluni/src/main/java/java/lang/SecurityManager.java
index 0cf702e..b7053e0 100644
--- a/ojluni/src/main/java/java/lang/SecurityManager.java
+++ b/ojluni/src/main/java/java/lang/SecurityManager.java
@@ -30,6 +30,10 @@
 import java.io.FileDescriptor;
 import java.net.InetAddress;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// SecurityManager can only check access by Java code, so it can be bypassed by using
+// native code.  Applications should rely on Android permissions, process separation,
+// other other methods for security purposes.
 /**
  * Legacy security code; do not use.
  *
diff --git a/ojluni/src/main/java/java/lang/System.java b/ojluni/src/main/java/java/lang/System.java
index 6e8f74f..ef08be0 100644
--- a/ojluni/src/main/java/java/lang/System.java
+++ b/ojluni/src/main/java/java/lang/System.java
@@ -989,7 +989,7 @@
         }
         p.put("os.version", info.release);
 
-        // Undocumented Android-only properties.
+        // Android-added: Undocumented properties that exist only on Android.
         p.put("android.icu.library.version", ICU.getIcuVersion());
         p.put("android.icu.unicode.version", ICU.getUnicodeVersion());
         p.put("android.icu.cldr.version", ICU.getCldrVersion());
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index a6301b5..0419ede 100644
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -1081,7 +1081,9 @@
         ThreadGroup g;
         checkAccess();
         if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
-            throw new IllegalArgumentException();
+            // Android-changed: Improve exception message when the new priority
+            // is out of bounds.
+            throw new IllegalArgumentException("Priority out of range: " + newPriority);
         }
         if((g = getThreadGroup()) != null) {
             if (newPriority > g.getMaxPriority()) {
diff --git a/ojluni/src/main/java/java/lang/invoke/CallSite.java b/ojluni/src/main/java/java/lang/invoke/CallSite.java
index b2226bf..85b4bb9 100644
--- a/ojluni/src/main/java/java/lang/invoke/CallSite.java
+++ b/ojluni/src/main/java/java/lang/invoke/CallSite.java
@@ -260,7 +260,7 @@
         }
     }
 
-    /* Android-changed: not used. */
+    // Android-changed: not used.
     // /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
     // /*package-private*/
     // static Empty uninitializedCallSite() {
@@ -292,7 +292,7 @@
         UNSAFE.putObjectVolatile(this, TARGET_OFFSET, newTarget);
     }
 
-    /* Android-changed: not used. */
+    // Android-changed: not used.
     // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
     // static CallSite makeSite(MethodHandle bootstrapMethod,
     //                          // Callee information:
diff --git a/ojluni/src/main/java/java/lang/ref/Reference.java b/ojluni/src/main/java/java/lang/ref/Reference.java
index 99adb36..d628fab 100644
--- a/ojluni/src/main/java/java/lang/ref/Reference.java
+++ b/ojluni/src/main/java/java/lang/ref/Reference.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/java/lang/reflect/ReflectPermission.java b/ojluni/src/main/java/java/lang/reflect/ReflectPermission.java
index 96a2d21..a5e5be1 100644
--- a/ojluni/src/main/java/java/lang/reflect/ReflectPermission.java
+++ b/ojluni/src/main/java/java/lang/reflect/ReflectPermission.java
@@ -25,6 +25,8 @@
 
 package java.lang.reflect;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/net/DatagramSocket.java b/ojluni/src/main/java/java/net/DatagramSocket.java
index 34f3a2d..31a4db4 100755
--- a/ojluni/src/main/java/java/net/DatagramSocket.java
+++ b/ojluni/src/main/java/java/net/DatagramSocket.java
@@ -1347,17 +1347,16 @@
         factory = fac;
     }
 
+    // Android-added: for testing and internal use.
     /**
-     * Android-added: for testing and internal use.
-     *
      * @hide internal use only
      */
     public FileDescriptor getFileDescriptor$() {
         return impl.fd;
     }
 
+    // Android-added: setNetworkInterface() to set the network interface used by this socket.
     /**
-     * Android-added:
      * Sets the network interface used by this socket.  Any packets sent
      * via this socket are transmitted via the specified interface.  Any
      * packets received by this socket will come from the specified
diff --git a/ojluni/src/main/java/java/net/Inet6Address.java b/ojluni/src/main/java/java/net/Inet6Address.java
index 51b0927..ee946ee 100644
--- a/ojluni/src/main/java/java/net/Inet6Address.java
+++ b/ojluni/src/main/java/java/net/Inet6Address.java
@@ -262,7 +262,8 @@
             }
         }
 
-        /* ----- Android-removed -----
+        // Android-removed: getnameinfo returns smarter representations than getHostAddress()
+        /*
         String getHostAddress() {
             String s = numericToTextFormat(ipaddress);
             if (scope_ifname != null) { // must check this first
@@ -271,7 +272,8 @@
                 s = s + "%" + scope_id;
             }
             return s;
-        } */
+        }
+        */
 
         public boolean equals(Object o) {
             if (! (o instanceof Inet6AddressHolder)) {
@@ -870,7 +872,7 @@
      */
     @Override
     public String getHostAddress() {
-        // Android-changed: getnameinfo returns smarter representations
+        // Android-changed: getnameinfo returns smarter representations than getHostAddress()
         // return holder6.getHostAddress();
         return Libcore.os.getnameinfo(this, NI_NUMERICHOST); // Can't throw.
     }
diff --git a/ojluni/src/main/java/java/net/NetPermission.java b/ojluni/src/main/java/java/net/NetPermission.java
index 8eb7892..b5a0eab 100644
--- a/ojluni/src/main/java/java/net/NetPermission.java
+++ b/ojluni/src/main/java/java/net/NetPermission.java
@@ -27,6 +27,8 @@
 
 import java.security.*;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/net/ServerSocket.java b/ojluni/src/main/java/java/net/ServerSocket.java
index 670acf2..20ae95a 100644
--- a/ojluni/src/main/java/java/net/ServerSocket.java
+++ b/ojluni/src/main/java/java/net/ServerSocket.java
@@ -922,9 +922,8 @@
         /* Not implemented yet */
     }
 
+    // Android-added: for testing and internal use.
     /**
-     * Android-added: for testing and internal use.
-     *
      * @hide internal use only
      */
     public FileDescriptor getFileDescriptor$() {
diff --git a/ojluni/src/main/java/java/net/Socket.java b/ojluni/src/main/java/java/net/Socket.java
index 9d566b1..03e2b71 100644
--- a/ojluni/src/main/java/java/net/Socket.java
+++ b/ojluni/src/main/java/java/net/Socket.java
@@ -1768,9 +1768,8 @@
         /* Not implemented yet */
     }
 
+    // Android-added: for testing and internal use.
     /**
-     * Android-added: for testing and internal use.
-     *
      * @hide internal use only
      */
     public FileDescriptor getFileDescriptor$() {
diff --git a/ojluni/src/main/java/java/net/SocketPermission.java b/ojluni/src/main/java/java/net/SocketPermission.java
index cdd9f15..2195ecc 100644
--- a/ojluni/src/main/java/java/net/SocketPermission.java
+++ b/ojluni/src/main/java/java/net/SocketPermission.java
@@ -28,6 +28,8 @@
 import java.security.Permission;
 
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/net/SocketTimeoutException.java b/ojluni/src/main/java/java/net/SocketTimeoutException.java
index 3b5b50a..2c61415 100644
--- a/ojluni/src/main/java/java/net/SocketTimeoutException.java
+++ b/ojluni/src/main/java/java/net/SocketTimeoutException.java
@@ -50,11 +50,13 @@
     public SocketTimeoutException() {}
 
     /** @hide */
+    // Android-added: Additional constructor for internal use.
     public SocketTimeoutException(Throwable cause) {
         super(cause);
     }
 
     /** @hide */
+    // Android-added: Additional constructor for internal use.
     public SocketTimeoutException(String msg, Throwable cause) {
         super(msg, cause);
     }
diff --git a/ojluni/src/main/java/java/net/SocksSocketImpl.java b/ojluni/src/main/java/java/net/SocksSocketImpl.java
index f1b29b0..a81e219 100644
--- a/ojluni/src/main/java/java/net/SocksSocketImpl.java
+++ b/ojluni/src/main/java/java/net/SocksSocketImpl.java
@@ -347,8 +347,9 @@
                                       epoint.getPort());
         }
         if (server == null) {
+            // Android-removed: Logic to establish proxy connection based on default ProxySelector
             /*
-             * Android-changed: Removed code that tried to establish proxy connection if
+             * Removed code that tried to establish proxy connection if
              * ProxySelector#getDefault() is not null.
              * This was never the case in previous android releases, was causing
              * issues and therefore was removed.
diff --git a/ojluni/src/main/java/java/net/URLClassLoader.java b/ojluni/src/main/java/java/net/URLClassLoader.java
index 226492d..edb9b88 100644
--- a/ojluni/src/main/java/java/net/URLClassLoader.java
+++ b/ojluni/src/main/java/java/net/URLClassLoader.java
@@ -190,8 +190,8 @@
         if (security != null) {
             security.checkCreateClassLoader();
         }
-        ucp = new URLClassPath(urls, factory);
         acc = AccessController.getContext();
+        ucp = new URLClassPath(urls, factory, acc);
     }
 
     /* A map (used as a set) to keep track of closeable local resources
diff --git a/ojluni/src/main/java/java/security/AccessControlContext.java b/ojluni/src/main/java/java/security/AccessControlContext.java
index e95cff2..506898f 100644
--- a/ojluni/src/main/java/java/security/AccessControlContext.java
+++ b/ojluni/src/main/java/java/security/AccessControlContext.java
@@ -30,6 +30,8 @@
 import java.util.List;
 
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/AccessController.java b/ojluni/src/main/java/java/security/AccessController.java
index b4d544c..ad844ba 100644
--- a/ojluni/src/main/java/java/security/AccessController.java
+++ b/ojluni/src/main/java/java/security/AccessController.java
@@ -27,6 +27,8 @@
 package java.security;
 
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/AllPermission.java b/ojluni/src/main/java/java/security/AllPermission.java
index 20e452b..61bcaea 100644
--- a/ojluni/src/main/java/java/security/AllPermission.java
+++ b/ojluni/src/main/java/java/security/AllPermission.java
@@ -25,6 +25,8 @@
 
 package java.security;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/AuthProvider.java b/ojluni/src/main/java/java/security/AuthProvider.java
index 23ddb0a..e87daa9 100644
--- a/ojluni/src/main/java/java/security/AuthProvider.java
+++ b/ojluni/src/main/java/java/security/AuthProvider.java
@@ -29,6 +29,8 @@
 import javax.security.auth.login.LoginException;
 import javax.security.auth.callback.CallbackHandler;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/BasicPermission.java b/ojluni/src/main/java/java/security/BasicPermission.java
index 0a069b0..1836b10 100644
--- a/ojluni/src/main/java/java/security/BasicPermission.java
+++ b/ojluni/src/main/java/java/security/BasicPermission.java
@@ -25,6 +25,8 @@
 
 package java.security;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/CodeSource.java b/ojluni/src/main/java/java/security/CodeSource.java
index 7396d91..fce8aa1 100644
--- a/ojluni/src/main/java/java/security/CodeSource.java
+++ b/ojluni/src/main/java/java/security/CodeSource.java
@@ -35,6 +35,8 @@
 import java.io.IOException;
 import java.security.cert.*;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/DomainCombiner.java b/ojluni/src/main/java/java/security/DomainCombiner.java
index 5426bf6..e9c010f 100644
--- a/ojluni/src/main/java/java/security/DomainCombiner.java
+++ b/ojluni/src/main/java/java/security/DomainCombiner.java
@@ -25,6 +25,8 @@
 
 package java.security;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/IdentityScope.java b/ojluni/src/main/java/java/security/IdentityScope.java
index 65f4e98..61d37cb 100644
--- a/ojluni/src/main/java/java/security/IdentityScope.java
+++ b/ojluni/src/main/java/java/security/IdentityScope.java
@@ -87,6 +87,8 @@
         } else {
 
             try {
+                // Android-changed: Actually set the system scope after initializing it
+                // Class.forName(classname);
                 scope = (IdentityScope) Class.forName(classname).newInstance();
             } catch (Exception e) {
                 //Security.error("unable to establish a system scope from " +
diff --git a/ojluni/src/main/java/java/security/KeyPairGenerator.java b/ojluni/src/main/java/java/security/KeyPairGenerator.java
index 1e46cee..68ab5e9 100644
--- a/ojluni/src/main/java/java/security/KeyPairGenerator.java
+++ b/ojluni/src/main/java/java/security/KeyPairGenerator.java
@@ -34,11 +34,6 @@
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
 
-/*
-Android-removed: this debugging mechanism is not supported in Android.
-import sun.security.util.Debug;
-*/
-
 /**
  * The KeyPairGenerator class is used to generate pairs of
  * public and private keys. Key pair generators are constructed using the
@@ -149,8 +144,8 @@
 
 public abstract class KeyPairGenerator extends KeyPairGeneratorSpi {
 
+    // Android-removed: this debugging mechanism is not used in Android.
     /*
-    Android-removed: this debugging mechanism is not supported in Android.
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -199,8 +194,8 @@
         }
         kpg.provider = instance.provider;
 
+        // Android-removed: this debugging mechanism is not used in Android.
         /*
-        Android-removed: this debugging mechanism is not supported in Android.
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyPairGenerator." + algorithm +
                 " algorithm from: " + kpg.provider.getName());
@@ -598,8 +593,8 @@
             this.serviceIterator = serviceIterator;
             initType = I_NONE;
 
+            // Android-removed: this debugging mechanism is not used in Android.
             /*
-            Android-removed: this debugging mechanism is not supported in Android.
             if (!skipDebug && pdebug != null) {
                 pdebug.println("KeyPairGenerator." + algorithm +
                     " algorithm from: " + provider.getName());
diff --git a/ojluni/src/main/java/java/security/KeyStoreSpi.java b/ojluni/src/main/java/java/security/KeyStoreSpi.java
index 4caa59c..531a983 100644
--- a/ojluni/src/main/java/java/security/KeyStoreSpi.java
+++ b/ojluni/src/main/java/java/security/KeyStoreSpi.java
@@ -34,6 +34,7 @@
 import java.security.cert.CertificateException;
 
 import javax.crypto.SecretKey;
+
 import javax.security.auth.callback.*;
 
 /**
@@ -451,34 +452,43 @@
             return null;
         }
 
-        if (protParam != null &&
-                !(protParam instanceof KeyStore.PasswordProtection)) {
-            throw new UnsupportedOperationException();
+        if (protParam == null) {
+            if (engineIsCertificateEntry(alias)) {
+                return new KeyStore.TrustedCertificateEntry
+                                (engineGetCertificate(alias));
+            // Android-removed: Allow access to entries with no password.
+            // } else {
+            //    throw new UnrecoverableKeyException
+            //            ("requested entry requires a password");
+            }
         }
 
-        if (engineIsCertificateEntry(alias)) {
-            if (protParam == null) {
-                return new KeyStore.TrustedCertificateEntry
-                        (engineGetCertificate(alias));
-            } else {
+        // Android-changed: Add protParam == null to allow access to entries with no password.
+        if ((protParam == null) || protParam instanceof KeyStore.PasswordProtection) {
+            if (engineIsCertificateEntry(alias)) {
                 throw new UnsupportedOperationException
                     ("trusted certificate entries are not password-protected");
+            } else if (engineIsKeyEntry(alias)) {
+                // Android-changed: Allow access to entries with no password.
+                // KeyStore.PasswordProtection pp =
+                //         (KeyStore.PasswordProtection)protParam;
+                // char[] password = pp.getPassword();
+                char[] password = null;
+                if (protParam != null) {
+                    KeyStore.PasswordProtection pp =
+                        (KeyStore.PasswordProtection)protParam;
+                    password = pp.getPassword();
+                }
+                Key key = engineGetKey(alias, password);
+                if (key instanceof PrivateKey) {
+                    Certificate[] chain = engineGetCertificateChain(alias);
+                    return new KeyStore.PrivateKeyEntry((PrivateKey)key, chain);
+                } else if (key instanceof SecretKey) {
+                    return new KeyStore.SecretKeyEntry((SecretKey)key);
+                }
             }
-        } else if (engineIsKeyEntry(alias)) {
-          char[] password = null;
-          if (protParam != null) {
-              KeyStore.PasswordProtection pp =
-                      (KeyStore.PasswordProtection)protParam;
-              password = pp.getPassword();
-          }
-          Key key = engineGetKey(alias, password);
-          if (key instanceof PrivateKey) {
-              Certificate[] chain = engineGetCertificateChain(alias);
-              return new KeyStore.PrivateKeyEntry((PrivateKey)key, chain);
-          } else if (key instanceof SecretKey) {
-              return new KeyStore.SecretKeyEntry((SecretKey)key);
-          }
         }
+
         throw new UnsupportedOperationException();
     }
 
@@ -514,6 +524,7 @@
             pProtect = (KeyStore.PasswordProtection)protParam;
         }
 
+        // BEGIN Android-changed: Allow access to entries with no password.
         char[] password = (pProtect == null) ? null : pProtect.getPassword();
         // set entry
         if (entry instanceof KeyStore.TrustedCertificateEntry) {
@@ -536,6 +547,7 @@
                 (Certificate[])null);
             return;
         }
+        // END Android-changed: Allow access to entries with no password.
 
         throw new KeyStoreException
                 ("unsupported entry type: " + entry.getClass().getName());
diff --git a/ojluni/src/main/java/java/security/MessageDigest.java b/ojluni/src/main/java/java/security/MessageDigest.java
index df6c456..8e5dab1 100644
--- a/ojluni/src/main/java/java/security/MessageDigest.java
+++ b/ojluni/src/main/java/java/security/MessageDigest.java
@@ -35,10 +35,6 @@
 
 import java.nio.ByteBuffer;
 
-/*
-Android-removed: this debugging mechanism is not available in Android.
-import sun.security.util.Debug;
-*/
 /**
  * This MessageDigest class provides applications the functionality of a
  * message digest algorithm, such as SHA-1 or SHA-256.
@@ -134,8 +130,8 @@
 
 public abstract class MessageDigest extends MessageDigestSpi {
 
+    // Android-removed: this debugging mechanism is not used in Android.
     /*
-    Android-removed: this debugging mechanism is not available in Android.
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -205,8 +201,8 @@
             }
             md.provider = (Provider)objs[1];
 
+            // Android-removed: this debugging mechanism is not used in Android.
             /*
-            Android-removed: this debugging mechanism is not available in Android.
             if (!skipDebug && pdebug != null) {
                 pdebug.println("MessageDigest." + algorithm +
                     " algorithm from: " + md.provider.getName());
@@ -450,6 +446,7 @@
      * Returns a string representation of this message digest object.
      */
     public String toString() {
+        // BEGIN Android-changed: Use StringBuilder instead of a ByteArrayOutputStream.
         StringBuilder builder = new StringBuilder();
         builder.append(algorithm);
         builder.append(" Message Digest from ");
@@ -466,6 +463,7 @@
         }
 
         return builder.toString();
+        // END Android-changed: Use StringBuilder instead of a ByteArrayOutputStream.
     }
 
     /**
diff --git a/ojluni/src/main/java/java/security/Permission.java b/ojluni/src/main/java/java/security/Permission.java
index 8d170c0..54163b9 100644
--- a/ojluni/src/main/java/java/security/Permission.java
+++ b/ojluni/src/main/java/java/security/Permission.java
@@ -25,6 +25,8 @@
 
 package java.security;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/PermissionCollection.java b/ojluni/src/main/java/java/security/PermissionCollection.java
index e356524..f1015e3 100644
--- a/ojluni/src/main/java/java/security/PermissionCollection.java
+++ b/ojluni/src/main/java/java/security/PermissionCollection.java
@@ -27,6 +27,8 @@
 
 import java.util.*;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/Permissions.java b/ojluni/src/main/java/java/security/Permissions.java
index 7411e06..9796f01 100644
--- a/ojluni/src/main/java/java/security/Permissions.java
+++ b/ojluni/src/main/java/java/security/Permissions.java
@@ -29,6 +29,8 @@
 import java.io.Serializable;
 
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/Policy.java b/ojluni/src/main/java/java/security/Policy.java
index 71c6cd0..cb7fb3b 100644
--- a/ojluni/src/main/java/java/security/Policy.java
+++ b/ojluni/src/main/java/java/security/Policy.java
@@ -29,9 +29,8 @@
 
 import java.util.Enumeration;
 
-
-/* Not used on Android, removed most of the code and made the class methods no-ops */
-
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/PrivilegedAction.java b/ojluni/src/main/java/java/security/PrivilegedAction.java
index bef7e44..5844b4d 100644
--- a/ojluni/src/main/java/java/security/PrivilegedAction.java
+++ b/ojluni/src/main/java/java/security/PrivilegedAction.java
@@ -26,6 +26,8 @@
 package java.security;
 
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/PrivilegedActionException.java b/ojluni/src/main/java/java/security/PrivilegedActionException.java
index 83d855a..b1eb28f 100644
--- a/ojluni/src/main/java/java/security/PrivilegedActionException.java
+++ b/ojluni/src/main/java/java/security/PrivilegedActionException.java
@@ -25,6 +25,8 @@
 
 package java.security;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  *
diff --git a/ojluni/src/main/java/java/security/PrivilegedExceptionAction.java b/ojluni/src/main/java/java/security/PrivilegedExceptionAction.java
index bae883e..4023150 100644
--- a/ojluni/src/main/java/java/security/PrivilegedExceptionAction.java
+++ b/ojluni/src/main/java/java/security/PrivilegedExceptionAction.java
@@ -26,6 +26,8 @@
 package java.security;
 
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/ProtectionDomain.java b/ojluni/src/main/java/java/security/ProtectionDomain.java
index 7cacc35..9e117a6 100644
--- a/ojluni/src/main/java/java/security/ProtectionDomain.java
+++ b/ojluni/src/main/java/java/security/ProtectionDomain.java
@@ -26,6 +26,8 @@
 
 package java.security;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/Provider.java b/ojluni/src/main/java/java/security/Provider.java
index d1fbd29..cbf37db 100644
--- a/ojluni/src/main/java/java/security/Provider.java
+++ b/ojluni/src/main/java/java/security/Provider.java
@@ -95,6 +95,10 @@
     // Declare serialVersionUID to be compatible with JDK1.1
     static final long serialVersionUID = -4298000515446427739L;
 
+    // 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
     private volatile boolean registered = false;
 
     private static final sun.security.util.Debug debug =
@@ -699,6 +703,7 @@
 
     private void readObject(ObjectInputStream in)
                 throws IOException, ClassNotFoundException {
+        // Android-added: Provider registration
         registered = false;
         Map<Object,Object> copy = new HashMap<>();
         for (Map.Entry<Object,Object> entry : super.entrySet()) {
@@ -712,6 +717,7 @@
     }
 
     private boolean checkLegacy(Object key) {
+        // Android-added: Provider registration
         if (registered) {
             Security.increaseVersion();
         }
@@ -736,6 +742,7 @@
         for (Map.Entry<?,?> e : t.entrySet()) {
             implPut(e.getKey(), e.getValue());
         }
+        // Android-added: Provider registration
         if (registered) {
             Security.increaseVersion();
         }
@@ -879,6 +886,7 @@
         serviceSet = null;
         super.clear();
         putId();
+        // Android-added: Provider registration
         if (registered) {
           Security.increaseVersion();
         }
@@ -1183,6 +1191,7 @@
             String key = type + "." + algorithm + " " + entry.getKey();
             super.put(key, entry.getValue());
         }
+        // Android-added: Provider registration
         if (registered) {
             Security.increaseVersion();
         }
@@ -1204,6 +1213,7 @@
             String key = type + "." + algorithm + " " + entry.getKey();
             super.remove(key);
         }
+        // Android-added: Provider registration
         if (registered) {
           Security.increaseVersion();
         }
@@ -1872,6 +1882,7 @@
 
     }
 
+    // BEGIN Android-added: Provider registration
     /**
      * @hide
      */
@@ -1910,4 +1921,5 @@
         // stored field, if the services didn't change in the meantime.
         getServices();
     }
+    // END Android-added: Provider registration
 }
diff --git a/ojluni/src/main/java/java/security/SecureRandom.java b/ojluni/src/main/java/java/security/SecureRandom.java
index 78eac68..0852cbd 100644
--- a/ojluni/src/main/java/java/security/SecureRandom.java
+++ b/ojluni/src/main/java/java/security/SecureRandom.java
@@ -99,7 +99,7 @@
 
 public class SecureRandom extends java.util.Random {
 
-    // Android-removed: this debugging mechanism is not supported in Android.
+    // Android-removed: this debugging mechanism is not used in Android.
     /*
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
@@ -203,7 +203,7 @@
     private void getDefaultPRNG(boolean setSeed, byte[] seed) {
         String prng = getPrngAlgorithm();
         if (prng == null) {
-            // Android-changed, should never happen
+            // Android-changed: This should never happen, we always provide a SecureRandom
             throw new IllegalStateException("No SecureRandom implementation!");
         } else {
             try {
@@ -300,6 +300,7 @@
             instance.provider, algorithm);
     }
 
+    // BEGIN Android-added: Support for Crypto provider workaround
     /**
      * Maximum SDK version for which the workaround for the Crypto provider is in place.
      *
@@ -332,6 +333,7 @@
     public static int getSdkTargetForCryptoProviderWorkaround() {
         return sdkTargetForCryptoProviderWorkaround;
     }
+    // END Android-added: Support for Crypto provider workaround
 
     /**
      * Returns a SecureRandom object that implements the specified
@@ -383,6 +385,7 @@
                     SecureRandomSpi.class, algorithm, provider);
             return new SecureRandom((SecureRandomSpi) instance.impl,
                     instance.provider, algorithm);
+        // BEGIN Android-added: Crypto provider deprecation
         } catch (NoSuchProviderException nspe) {
             if ("Crypto".equals(provider)) {
                 System.logE(" ********** PLEASE READ ************ ");
@@ -424,6 +427,7 @@
         return new SecureRandom(
                 (SecureRandomSpi) instance.impl, instance.provider, algorithm);
     }
+    // END Android-added: Crypto provider deprecation
 
     /**
      * Returns a SecureRandom object that implements the specified
@@ -547,6 +551,9 @@
      * @param bytes the array to be filled in with random bytes.
      */
     @Override
+    // Android-changed: Added synchronized
+    // This method has been synchronized at least since Cupcake, so it would probably
+    // lead to problems if it was removed.
     synchronized public void nextBytes(byte[] bytes) {
         secureRandomSpi.engineNextBytes(bytes);
     }
@@ -695,6 +702,7 @@
      */
     public static SecureRandom getInstanceStrong()
             throws NoSuchAlgorithmException {
+
         String property = AccessController.doPrivileged(
             new PrivilegedAction<String>() {
                 @Override
diff --git a/ojluni/src/main/java/java/security/Security.java b/ojluni/src/main/java/java/security/Security.java
index dc248eb..743cf36 100644
--- a/ojluni/src/main/java/java/security/Security.java
+++ b/ojluni/src/main/java/java/security/Security.java
@@ -48,9 +48,16 @@
 
 public final class Security {
 
+    // Android-added: Track the version to allow callers know when something has changed.
     private static final AtomicInteger version = new AtomicInteger();
 
+    // Android-removed: Debug is stubbed and disabled on Android.
+    // /* Are we debugging? -- for developers */
+    // private static final Debug sdebug =
+    //                     Debug.getInstance("properties");
+
     /* The java.security properties */
+    // Android-changed: Added final.
     private static final Properties props;
 
     // An element in the cache
@@ -60,12 +67,31 @@
     }
 
     static {
+// BEGIN Android-changed: doPrivileged is stubbed on Android.
+// Also, because props is final it must be assigned in the static block, not a method.
+        /*
+        // doPrivileged here because there are multiple
+        // things in initialize that might require privs.
+        // (the FileInputStream call and the File.exists call,
+        // the securityPropFile call, etc)
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                initialize();
+                return null;
+            }
+        });
+    }
+
+    private static void initialize() {
+        */
+// END Android-changed: doPrivileged is stubbed on Android.
         props = new Properties();
         boolean loadedProps = false;
+        // BEGIN Android-changed: Use a resource file, Android logging, and only one file.
         InputStream is = null;
         try {
             /*
-             * Android keeps the property file in a jar resource.
+             * Android keeps the property file in a resource file.
              */
             InputStream propStream = Security.class.getResourceAsStream("security.properties");
             if (propStream == null) {
@@ -84,6 +110,7 @@
                 } catch (IOException ignored) {}
             }
         }
+        // END Android-changed: Use a resource file, Android logging, and only one file.
 
         if (!loadedProps) {
             initializeStatic();
@@ -95,6 +122,15 @@
      * is not found.
      */
     private static void initializeStatic() {
+        // Android-changed: Use Conscrypt and BC, not the sun.security providers.
+        /*
+        props.put("security.provider.1", "sun.security.provider.Sun");
+        props.put("security.provider.2", "sun.security.rsa.SunRsaSign");
+        props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider");
+        props.put("security.provider.4", "com.sun.crypto.provider.SunJCE");
+        props.put("security.provider.5", "sun.security.jgss.SunProvider");
+        props.put("security.provider.6", "com.sun.security.sasl.Provider");
+        */
         props.put("security.provider.1", "com.android.org.conscrypt.OpenSSLProvider");
         props.put("security.provider.2", "sun.security.provider.CertPathProvider");
         props.put("security.provider.3", "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider");
@@ -247,15 +283,14 @@
     public static synchronized int insertProviderAt(Provider provider,
             int position) {
         String providerName = provider.getName();
-        // Android-removed
-        // Checks using SecurityManager, which is not functional in Android.
+        // Android-removed: Checks using SecurityManager, which is not functional in Android.
         // checkInsertProvider(providerName);
-        // Android-removed
         ProviderList list = Providers.getFullProviderList();
         ProviderList newList = ProviderList.insertAt(list, provider, position - 1);
         if (list == newList) {
             return -1;
         }
+        // Android-added: Version tracking call.
         increaseVersion();
         Providers.setProviderList(newList);
         return newList.getIndex(providerName) + 1;
@@ -331,10 +366,12 @@
      * @see #addProvider
      */
     public static synchronized void removeProvider(String name) {
-        check("removeProvider." + name);
+        // Android-removed: Checks using SecurityManager, which is not functional in Android.
+        // check("removeProvider." + name);
         ProviderList list = Providers.getFullProviderList();
         ProviderList newList = ProviderList.remove(list, name);
         Providers.setProviderList(newList);
+        // Android-added: Version tracking call.
         increaseVersion();
     }
 
@@ -685,8 +722,10 @@
      * @see java.security.SecurityPermission
      */
     public static void setProperty(String key, String datum) {
-        check("setProperty."+key);
+        // Android-removed: Checks using SecurityManager, which is not functional in Android.
+        // check("setProperty."+key);
         props.put(key, datum);
+        // Android-added: Version tracking call.
         increaseVersion();
         invalidateSMCache(key);  /* See below. */
     }
@@ -745,6 +784,8 @@
         }  /* if */
     }
 
+    // BEGIN Android-removed: SecurityManager is stubbed on Android.
+    /*
     private static void check(String directive) {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
@@ -752,6 +793,25 @@
         }
     }
 
+    private static void checkInsertProvider(String name) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            try {
+                security.checkSecurityAccess("insertProvider");
+            } catch (SecurityException se1) {
+                try {
+                    security.checkSecurityAccess("insertProvider." + name);
+                } catch (SecurityException se2) {
+                    // throw first exception, but add second to suppressed
+                    se1.addSuppressed(se2);
+                    throw se1;
+                }
+            }
+        }
+    }
+    */
+    // END Android-removed: SecurityManager is stubbed on Android.
+
     /*
     * Returns all providers who satisfy the specified
     * criterion.
@@ -1004,6 +1064,7 @@
         return Collections.unmodifiableSet(result);
     }
 
+    // BEGIN Android-added: Methods for version handling.
     /**
      * @hide
      */
@@ -1016,4 +1077,5 @@
     public static int getVersion() {
         return version.get();
     }
+    // END Android-added: Methods for version handling.
 }
diff --git a/ojluni/src/main/java/java/security/SecurityPermission.java b/ojluni/src/main/java/java/security/SecurityPermission.java
index 7d2ec47..f02755c 100644
--- a/ojluni/src/main/java/java/security/SecurityPermission.java
+++ b/ojluni/src/main/java/java/security/SecurityPermission.java
@@ -25,6 +25,8 @@
 
 package java.security;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/Signature.java b/ojluni/src/main/java/java/security/Signature.java
index 7e9f5a8..5a0e6a8 100644
--- a/ojluni/src/main/java/java/security/Signature.java
+++ b/ojluni/src/main/java/java/security/Signature.java
@@ -368,6 +368,8 @@
         do {
             Service s = t.next();
             if (isSpi(s)) {
+                // Android-changed: Delegate constructor only takes algorithm.
+                // return new Delegate(s, t, algorithm);
                 return new Delegate(algorithm);
             } else {
                 // must be a subclass of Signature, disable dynamic selection
@@ -1064,7 +1066,7 @@
      * @deprecated Deprecated.
      */
     @Deprecated
-    // Android-changed add "Deprecated."
+    // Android-changed: add "Deprecated."
     public final Object getParameter(String param)
             throws InvalidParameterException {
         return engineGetParameter(param);
@@ -1086,6 +1088,7 @@
         }
     }
 
+    // BEGIN Android-added: Allow access to the current SPI for testing purposes.
     /**
      * Returns the {@code SignatureSpi} backing this {@code Signature}.
      *
@@ -1094,6 +1097,7 @@
     public SignatureSpi getCurrentSpi() {
       return null;
     }
+    // END Android-added: Allow access to the current SPI for testing purposes.
 
     /*
      * The following class allows providers to extend from SignatureSpi
@@ -1114,25 +1118,43 @@
 
         // The provider implementation (delegate)
         // filled in once the provider is selected
-        // BEGIN Android-added
+        // BEGIN Android-note: Note on sigSpi invariants.
         // (Not necessarily Android specific)
         // Invariant to be preserved: sigSpi cannot be changed once it was assigned to something
-        // different than null and lock is null. That is the case when sigSpi is specified in the
-        // constructor.
-        // END Android-added
+        // different than null and lock is null. That is only the case when sigSpi is specified
+        // in the constructor.
+        // END Android-note: Note on sigSpi invariants.
         private SignatureSpi sigSpi;
 
         // lock for mutex during provider selection
         private final Object lock;
 
+        // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
+        // When only the algorithm is specified, we want to allow the Signature provider for that
+        // algorithm to change if multiple providers exist and they support different subsets of
+        // keys.  To that end, we don't hold an iterator and exhaust it when we need to choose
+        // a provider like the upstream implementation, we reestablish the list of providers
+        // each time.
+        /*
+        // next service to try in provider selection
+        // null once provider is selected
+        private Service firstService;
+
+        // remaining services to try in provider selection
+        // null once provider is selected
+        private Iterator<Service> serviceIterator;
+        */
+        // END Android-removed: Redo the provider selection logic to allow reselecting provider.
+
         // constructor
         Delegate(SignatureSpi sigSpi, String algorithm) {
             super(algorithm);
             this.sigSpi = sigSpi;
-            this.lock = null;
+            this.lock = null; // no lock needed
         }
 
         // used with delayed provider selection
+        // Android-changed: Remove Service and Iterator from constructor args.
         Delegate(String algorithm) {
             super(algorithm);
             this.lock = new Object();
@@ -1215,6 +1237,7 @@
                 */
                 // END Android-removed: this debugging mechanism is not supported in Android.
                 Exception lastException = null;
+// BEGIN Android-changed: Provider selection; loop over a new list each time.
                 List<Service> list;
                 if (((Signature)this).algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {
                     list = GetInstance.getServices(rsaIds);
@@ -1223,12 +1246,19 @@
                             ((Signature)this).algorithm);
                 }
                 for (Service s : list) {
+// END Android-changed: Provider selection; loop over a new list each time.
                     if (isSpi(s) == false) {
                         continue;
                     }
                     try {
                         sigSpi = newInstance(s);
                         provider = s.getProvider();
+                        // Android-removed: Provider selection; loop over a new list each time.
+                        /*
+                        // not needed any more
+                        firstService = null;
+                        serviceIterator = null;
+                        */
                         return;
                     } catch (NoSuchAlgorithmException e) {
                         lastException = e;
@@ -1246,11 +1276,14 @@
         private void chooseProvider(int type, Key key, SecureRandom random)
                 throws InvalidKeyException {
             synchronized (lock) {
+                // Android-changed: Use the currently-selected provider only if no key was provided.
+                // if (sigSpi != null) {
                 if (sigSpi != null && key == null) {
                     init(sigSpi, type, key, random);
                     return;
                 }
                 Exception lastException = null;
+// BEGIN Android-changed: Provider selection; loop over a new list each time.
                 List<Service> list;
                 if (((Signature)this).algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {
                     list = GetInstance.getServices(rsaIds);
@@ -1259,6 +1292,7 @@
                             ((Signature)this).algorithm);
                 }
                 for (Service s : list) {
+// END Android-changed: Provider selection; loop over a new list each time.
                     // if provider says it does not support this key, ignore it
                     if (s.supportsParameter(key) == false) {
                         continue;
@@ -1272,6 +1306,11 @@
                         init(spi, type, key, random);
                         provider = s.getProvider();
                         sigSpi = spi;
+                        // Android-removed: Provider selection; loop over a new list each time.
+                        /*
+                        firstService = null;
+                        serviceIterator = null;
+                        */
                         return;
                     } catch (Exception e) {
                         // NoSuchAlgorithmException from newInstance()
@@ -1280,6 +1319,7 @@
                         if (lastException == null) {
                             lastException = e;
                         }
+                        // Android-added: Throw InvalidKeyException immediately.
                         if (lastException instanceof InvalidKeyException) {
                           throw (InvalidKeyException)lastException;
                         }
@@ -1322,6 +1362,8 @@
 
         protected void engineInitVerify(PublicKey publicKey)
                 throws InvalidKeyException {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (sigSpi != null) {
             if (sigSpi != null && (lock == null || publicKey == null)) {
                 sigSpi.engineInitVerify(publicKey);
             } else {
@@ -1331,6 +1373,8 @@
 
         protected void engineInitSign(PrivateKey privateKey)
                 throws InvalidKeyException {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (sigSpi != null) {
             if (sigSpi != null && (lock == null || privateKey == null)) {
                 sigSpi.engineInitSign(privateKey);
             } else {
@@ -1340,6 +1384,8 @@
 
         protected void engineInitSign(PrivateKey privateKey, SecureRandom sr)
                 throws InvalidKeyException {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (sigSpi != null) {
             if (sigSpi != null  && (lock == null || privateKey == null)) {
                 sigSpi.engineInitSign(privateKey, sr);
             } else {
@@ -1409,6 +1455,7 @@
             return sigSpi.engineGetParameters();
         }
 
+        // BEGIN Android-added: Allow access to the current SPI for testing purposes.
         @Override
         public SignatureSpi getCurrentSpi() {
             if (lock == null) {
@@ -1418,6 +1465,7 @@
                 return sigSpi;
             }
         }
+        // END Android-added: Allow access to the current SPI for testing purposes.
     }
 
     // adapter for RSA/ECB/PKCS1Padding ciphers
diff --git a/ojluni/src/main/java/java/security/UnresolvedPermission.java b/ojluni/src/main/java/java/security/UnresolvedPermission.java
index 6d97fbe..6f3bf4a 100644
--- a/ojluni/src/main/java/java/security/UnresolvedPermission.java
+++ b/ojluni/src/main/java/java/security/UnresolvedPermission.java
@@ -34,6 +34,8 @@
 import java.lang.reflect.*;
 import java.security.cert.*;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/acl/Permission.java b/ojluni/src/main/java/java/security/acl/Permission.java
index cd84a48..72412de 100644
--- a/ojluni/src/main/java/java/security/acl/Permission.java
+++ b/ojluni/src/main/java/java/security/acl/Permission.java
@@ -25,6 +25,8 @@
 
 package java.security.acl;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/security/interfaces/DSAParams.java b/ojluni/src/main/java/java/security/interfaces/DSAParams.java
index b672ad5..8c46ed5 100644
--- a/ojluni/src/main/java/java/security/interfaces/DSAParams.java
+++ b/ojluni/src/main/java/java/security/interfaces/DSAParams.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.  
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/java/security/spec/ECParameterSpec.java b/ojluni/src/main/java/java/security/spec/ECParameterSpec.java
index 12e252b..65bd027 100644
--- a/ojluni/src/main/java/java/security/spec/ECParameterSpec.java
+++ b/ojluni/src/main/java/java/security/spec/ECParameterSpec.java
@@ -111,7 +111,9 @@
     public int getCofactor() {
         return h;
     }
-    // BEGIN Android-changed
+    // BEGIN Android-added: Store the curve name as part of the parameters
+    // Knowing the name of the curve sometimes allows implementations to operate
+    // more efficiently.
     private String curveName;
 
     /**
@@ -132,5 +134,5 @@
     public String getCurveName() {
         return curveName;
     }
-    // END Android-changed
+    // END Android-added: Store the curve name as part of the parameters
 }
diff --git a/ojluni/src/main/java/java/sql/SQLPermission.java b/ojluni/src/main/java/java/sql/SQLPermission.java
index 050f763..505202c 100644
--- a/ojluni/src/main/java/java/sql/SQLPermission.java
+++ b/ojluni/src/main/java/java/sql/SQLPermission.java
@@ -27,6 +27,8 @@
 
 import java.security.*;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/text/DateFormatSymbols.java b/ojluni/src/main/java/java/text/DateFormatSymbols.java
index aa57aad..96a966c 100644
--- a/ojluni/src/main/java/java/text/DateFormatSymbols.java
+++ b/ojluni/src/main/java/java/text/DateFormatSymbols.java
@@ -865,35 +865,17 @@
         }
     }
 
+    // BEGIN Android-changed: extract initialization of zoneStrings to separate method.
     private final synchronized String[][] internalZoneStrings() {
         if (zoneStrings == null) {
             zoneStrings = TimeZoneNames.getZoneStrings(locale);
-            // If icu4c doesn't have a name, our array contains a null. TimeZone.getDisplayName
-            // knows how to format GMT offsets (and, unlike icu4c, has accurate data). http://b/8128460.
-            for (String[] zone : zoneStrings) {
-                String id = zone[0];
-                if (zone[1] == null) {
-                    zone[1] =
-                        TimeZone.getTimeZone(id).getDisplayName(false, TimeZone.LONG, locale);
-                }
-                if (zone[2] == null) {
-                    zone[2] =
-                        TimeZone.getTimeZone(id).getDisplayName(false, TimeZone.SHORT, locale);
-                }
-                if (zone[3] == null) {
-                    zone[3] = TimeZone.getTimeZone(id).getDisplayName(true, TimeZone.LONG, locale);
-                }
-                if (zone[4] == null) {
-                    zone[4] =
-                        TimeZone.getTimeZone(id).getDisplayName(true, TimeZone.SHORT, locale);
-                }
-            }
         }
         return zoneStrings;
     }
 
     private final String[][] getZoneStringsImpl(boolean needsCopy) {
         String[][] zoneStrings = internalZoneStrings();
+        // END Android-changed: extract initialization of zoneStrings to separate method.
 
         if (!needsCopy) {
             return zoneStrings;
@@ -964,6 +946,7 @@
      * @since 1.6
      */
     private void writeObject(ObjectOutputStream stream) throws IOException {
+        // Android-changed: extract initialization of zoneStrings to separate method.
         internalZoneStrings();
         stream.defaultWriteObject();
     }
diff --git a/ojluni/src/main/java/java/text/SimpleDateFormat.java b/ojluni/src/main/java/java/text/SimpleDateFormat.java
index 700d5ca..6ae9057 100644
--- a/ojluni/src/main/java/java/text/SimpleDateFormat.java
+++ b/ojluni/src/main/java/java/text/SimpleDateFormat.java
@@ -1212,18 +1212,18 @@
             break;
 
         case PATTERN_MONTH: // 'M'
-        {
-            current = formatMonth(count, value, maxIntCount, buffer, useDateFormatSymbols,
-                    false /* standalone */);
+            if (useDateFormatSymbols) {
+                current = formatMonth(count, value, maxIntCount, buffer, useDateFormatSymbols,
+                        false /* standalone */);
+            }
             break;
-        }
 
         case PATTERN_MONTH_STANDALONE: // 'L'
-        {
-            current = formatMonth(count, value, maxIntCount, buffer, useDateFormatSymbols,
-                    true /* standalone */);
+            if (useDateFormatSymbols) {
+                current = formatMonth(count, value, maxIntCount, buffer, useDateFormatSymbols,
+                        true /* standalone */);
+            }
             break;
-        }
 
         case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
             if (current == null) {
@@ -1237,16 +1237,16 @@
             break;
 
         case PATTERN_DAY_OF_WEEK: // 'E'
-        {
-            current = formatWeekday(count, value, useDateFormatSymbols, false /* standalone */);
+            if (current == null) {
+                current = formatWeekday(count, value, useDateFormatSymbols, false /* standalone */);
+            }
             break;
-        }
 
         case PATTERN_STANDALONE_DAY_OF_WEEK: // 'c'
-        {
-            current = formatWeekday(count, value, useDateFormatSymbols, true /* standalone */);
+            if (current == null) {
+                current = formatWeekday(count, value, useDateFormatSymbols, true /* standalone */);
+            }
             break;
-        }
 
         case PATTERN_AM_PM:    // 'a'
             if (useDateFormatSymbols) {
diff --git a/ojluni/src/main/java/java/time/chrono/HijrahChronology.java b/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
index 98b79c4..e7b3554 100644
--- a/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
+++ b/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
@@ -544,7 +544,7 @@
     //-----------------------------------------------------------------------
     @Override
     public boolean isLeapYear(long prolepticYear) {
-      checkCalendarInit();
+        checkCalendarInit();
         if (prolepticYear < getMinimumYear() || prolepticYear > getMaximumYear()) {
             return false;
         }
diff --git a/ojluni/src/main/java/java/time/chrono/JapaneseDate.java b/ojluni/src/main/java/java/time/chrono/JapaneseDate.java
index 45e6602..143c4a4 100644
--- a/ojluni/src/main/java/java/time/chrono/JapaneseDate.java
+++ b/ojluni/src/main/java/java/time/chrono/JapaneseDate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -432,7 +432,11 @@
                 field == ALIGNED_WEEK_OF_MONTH || field == ALIGNED_WEEK_OF_YEAR) {
             return false;
         }
-        return ChronoLocalDate.super.isSupported(field);
+        // Android-changed: Apply upstream OpenJDK 9 compilation fix.
+        // Applied OpenJDK 9 change from http://hg.openjdk.java.net/jdk9/dev/jdk/rev/2b7b09c81bf1
+        // On OpenJDK 8, either version is supported and has the same behavior.
+        // return ChronoLocalDate.super.isSupported(field);
+        return super.isSupported(field);
     }
 
     @Override
diff --git a/ojluni/src/main/java/java/util/ArrayList.java b/ojluni/src/main/java/java/util/ArrayList.java
index dd465c9..d65bf1f 100644
--- a/ojluni/src/main/java/java/util/ArrayList.java
+++ b/ojluni/src/main/java/java/util/ArrayList.java
@@ -103,8 +103,8 @@
  * @see     Vector
  * @since   1.2
  */
+// Android-changed: Inlined methods; CME in iterators; throw AIOOBE when toIndex < fromIndex.
 /*
- * Android-changed:
  * - AOSP commit 3be987f0f18648b3c532c8b89d09505e18594241
  *   Inline for improved performance:
  *   - checkForComodification
diff --git a/ojluni/src/main/java/java/util/Arrays.java b/ojluni/src/main/java/java/util/Arrays.java
index b4f52a4..72c5f93 100644
--- a/ojluni/src/main/java/java/util/Arrays.java
+++ b/ojluni/src/main/java/java/util/Arrays.java
@@ -124,11 +124,10 @@
         }
     }
 
+    // BEGIN Android-added: checkOffsetAndCount() helper method for AIOOBE enforcement.
     /**
      * Checks that the range described by {@code offset} and {@code count} doesn't exceed
      * {@code arrayLength}.
-     *
-     * Android-changed.
      * @hide
      */
     public static void checkOffsetAndCount(int arrayLength, int offset, int count) {
@@ -137,6 +136,7 @@
                     count);
         }
     }
+    // END Android-added: checkOffsetAndCount() helper method for AIOOBE enforcement.
 
     /*
      * Sorting methods. Note that all public "sort" methods take the
diff --git a/ojluni/src/main/java/java/util/Calendar.java b/ojluni/src/main/java/java/util/Calendar.java
index 2009123..b846211 100644
--- a/ojluni/src/main/java/java/util/Calendar.java
+++ b/ojluni/src/main/java/java/util/Calendar.java
@@ -1773,11 +1773,11 @@
     public void setTimeInMillis(long millis) {
         // If we don't need to recalculate the calendar field values,
         // do nothing.
-// BEGIN Android-changed: Removed ZoneInfo support
+// BEGIN Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
 //        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
 //            && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
         if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet) {
-// END Android-changed: Removed ZoneInfo support
+// END Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
 
             return;
         }
@@ -3508,7 +3508,7 @@
             catch (IllegalArgumentException e) {}
         }
 
-        // Android-changed: Removed ZoneInfo support/workaround.
+        // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
         // Write out the 1.1 FCS object.
         stream.defaultWriteObject();
     }
@@ -3560,7 +3560,7 @@
 
         serialVersionOnStream = currentSerialVersion;
 
-        // Android-changed: removed ZoneInfo support.
+        // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
 
         // If the deserialized object has a SimpleTimeZone, try to
         // replace it with a ZoneInfo equivalent (as of 1.4) in order
diff --git a/ojluni/src/main/java/java/util/Collections.java b/ojluni/src/main/java/java/util/Collections.java
index 315a7d1..9c379e6 100644
--- a/ojluni/src/main/java/java/util/Collections.java
+++ b/ojluni/src/main/java/java/util/Collections.java
@@ -151,7 +151,7 @@
     @SuppressWarnings("unchecked")
     public static <T extends Comparable<? super T>> void sort(List<T> list) {
         // Android-changed: Call sort(list, null) here to be consistent
-        // with that method's (Android-changed) behavior.
+        // with that method's (Android changed) behavior.
         // list.sort(null);
         sort(list, null);
     }
diff --git a/ojluni/src/main/java/java/util/EnumMap.java b/ojluni/src/main/java/java/util/EnumMap.java
index a2512a8..207ce62 100644
--- a/ojluni/src/main/java/java/util/EnumMap.java
+++ b/ojluni/src/main/java/java/util/EnumMap.java
@@ -750,9 +750,9 @@
      * The result is uncloned, cached, and shared by all callers.
      */
     private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
-        // Android-changed: Use JavaLangAccess directly instead of going through
-        // SharedSecrets.
-        return JavaLangAccess.getEnumConstantsShared(keyType);
+        // Android-changed: Use getEnumConstantsShared directly instead of going
+        // through SharedSecrets.
+        return keyType.getEnumConstantsShared();
     }
 
     private static final long serialVersionUID = 458661240069192865L;
diff --git a/ojluni/src/main/java/java/util/EnumSet.java b/ojluni/src/main/java/java/util/EnumSet.java
index 5d9311a..2443f1e 100644
--- a/ojluni/src/main/java/java/util/EnumSet.java
+++ b/ojluni/src/main/java/java/util/EnumSet.java
@@ -402,9 +402,9 @@
      * The result is uncloned, cached, and shared by all callers.
      */
     private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) {
-        // Android-changed: Use JavaLangAccess directly instead of going via
-        // SharedSecrets.
-        return java.lang.JavaLangAccess.getEnumConstantsShared(elementType);
+        // Android-changed: Use getEnumConstantsShared directly instead of going
+        // through SharedSecrets.
+        return elementType.getEnumConstantsShared();
     }
 
     /**
diff --git a/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java b/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java
index fef7eed..c569981 100644
--- a/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java
+++ b/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java
@@ -1574,10 +1574,14 @@
             zoneOffsets = new int[2];
         }
         if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
-            // Android-changed: remove ZoneInfo support.
-            zoneOffset = tz.getOffset(time);
-            zoneOffsets[0] = tz.getRawOffset();
-            zoneOffsets[1] = zoneOffset - zoneOffsets[0];
+            // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            // if (tz instanceof ZoneInfo) {
+            //     zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
+            // } else {
+                zoneOffset = tz.getOffset(time);
+                zoneOffsets[0] = tz.getRawOffset();
+                zoneOffsets[1] = zoneOffset - zoneOffsets[0];
+            // }
         }
         if (tzMask != 0) {
             if (isFieldSet(tzMask, ZONE_OFFSET)) {
@@ -1911,8 +1915,12 @@
         }
         int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
         if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
-            // Android-changed: remove ZoneInfo support
-            zone.getOffsets(millis - zone.getRawOffset(), zoneOffsets);
+            // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            // if (zone instanceof ZoneInfo) {
+            //     ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
+            // } else {
+                zone.getOffsets(millis - zone.getRawOffset(), zoneOffsets);
+            // }
         }
         if (tzMask != 0) {
             if (isFieldSet(tzMask, ZONE_OFFSET)) {
diff --git a/ojluni/src/main/java/java/util/LinkedHashMap.java b/ojluni/src/main/java/java/util/LinkedHashMap.java
index 3b5c3af..aec40bc 100644
--- a/ojluni/src/main/java/java/util/LinkedHashMap.java
+++ b/ojluni/src/main/java/java/util/LinkedHashMap.java
@@ -190,7 +190,7 @@
      * LinkedHashMap.Entry is now treated as intermediary node class
      * that can also be converted to tree form.
      *
-     * BEGIN Android-changed
+     // BEGIN Android-changed
      * LinkedHashMapEntry should not be renamed. Specifically, for
      * source compatibility with earlier versions of Android, this
      * nested class must not be named "Entry". Otherwise, it would
@@ -201,7 +201,7 @@
      * To compile, that code snippet's "LinkedHashMap.Entry" must
      * mean java.util.Map.Entry which is the compile time type of
      * entrySet()'s elements.
-     * END Android-changed
+     // END Android-changed
      *
      * The changes in node classes also require using two fields
      * (head, tail) rather than a pointer to a header node to maintain
diff --git a/ojluni/src/main/java/java/util/PropertyPermission.java b/ojluni/src/main/java/java/util/PropertyPermission.java
index 8b73ce1..ac7b521 100644
--- a/ojluni/src/main/java/java/util/PropertyPermission.java
+++ b/ojluni/src/main/java/java/util/PropertyPermission.java
@@ -27,6 +27,8 @@
 
 import java.security.*;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/java/util/ResourceBundle.java b/ojluni/src/main/java/java/util/ResourceBundle.java
index 886ffc1..6fff252 100644
--- a/ojluni/src/main/java/java/util/ResourceBundle.java
+++ b/ojluni/src/main/java/java/util/ResourceBundle.java
@@ -360,7 +360,8 @@
      */
     private volatile Set<String> keySet;
 
-    /* Android-changed: Removed used of ResourceBundleControlProvider.
+    // Android-changed: Removed use of ResourceBundleControlProvider.
+    /*
     private static final List<ResourceBundleControlProvider> providers;
 
     static {
diff --git a/ojluni/src/main/java/java/util/TimeZone.java b/ojluni/src/main/java/java/util/TimeZone.java
index c745291..6ad180b 100644
--- a/ojluni/src/main/java/java/util/TimeZone.java
+++ b/ojluni/src/main/java/java/util/TimeZone.java
@@ -39,20 +39,15 @@
 
 package java.util;
 
+import org.apache.harmony.luni.internal.util.TimezoneGetter;
+import android.icu.text.TimeZoneNames;
 import java.io.IOException;
 import java.io.Serializable;
 import java.time.ZoneId;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.lang.ref.SoftReference;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.concurrent.ConcurrentHashMap;
-import libcore.icu.TimeZoneNames;
 import libcore.io.IoUtils;
 import libcore.util.ZoneInfoDB;
-import sun.security.action.GetPropertyAction;
-import org.apache.harmony.luni.internal.util.TimezoneGetter;
 
 /**
  * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
@@ -387,35 +382,44 @@
      * @param locale the display locale.
      */
     public String getDisplayName(boolean daylightTime, int style, Locale locale) {
-        if (style != SHORT && style != LONG) {
-            throw new IllegalArgumentException("Illegal style: " + style);
+        // BEGIN Android-changed: implement using android.icu.text.TimeZoneNames
+        TimeZoneNames.NameType nameType;
+        switch (style) {
+            case SHORT:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.SHORT_DAYLIGHT
+                        : TimeZoneNames.NameType.SHORT_STANDARD;
+                break;
+            case LONG:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.LONG_DAYLIGHT
+                        : TimeZoneNames.NameType.LONG_STANDARD;
+                break;
+            default:
+                throw new IllegalArgumentException("Illegal style: " + style);
+        }
+        String canonicalID = android.icu.util.TimeZone.getCanonicalID(getID());
+        if (canonicalID != null) {
+            TimeZoneNames names = TimeZoneNames.getInstance(locale);
+            long now = System.currentTimeMillis();
+            String displayName = names.getDisplayName(canonicalID, nameType, now);
+            if (displayName != null) {
+                return displayName;
+            }
         }
 
-        // Android-changed: implement using libcore.icu.TimeZoneNames
-        String[][] zoneStrings = TimeZoneNames.getZoneStrings(locale);
-        String result = TimeZoneNames.getDisplayName(zoneStrings, getID(), daylightTime, style);
-        if (result != null) {
-            return result;
-        }
-
-        // If we get here, it's because icu4c has nothing for us. Most commonly, this is in the
-        // case of short names. For Pacific/Fiji, for example, icu4c has nothing better to offer
-        // than "GMT+12:00". Why do we re-do this work ourselves? Because we have up-to-date
-        // time zone transition data, which icu4c _doesn't_ use --- it uses its own baked-in copy,
-        // which only gets updated when we update icu4c. http://b/7955614 and http://b/8026776.
-
-        // TODO: should we generate these once, in TimeZoneNames.getDisplayName? Revisit when we
-        // upgrade to icu4c 50 and rewrite the underlying native code. See also the
-        // "element[j] != null" check in SimpleDateFormat.parseTimeZone, and the extra work in
-        // DateFormatSymbols.getZoneStrings.
+        // We get here if this is a custom timezone or ICU doesn't have name data for the specific
+        // style and locale.
         int offsetMillis = getRawOffset();
         if (daylightTime) {
             offsetMillis += getDSTSavings();
         }
         return createGmtOffsetString(true /* includeGmt */, true /* includeMinuteSeparator */,
                 offsetMillis);
+        // END Android-changed: implement using android.icu.text.TimeZoneNames
     }
 
+    // BEGIN Android-added: utility method to format an offset as a GMT offset string.
     /**
      * Returns a string representation of an offset from UTC.
      *
@@ -456,6 +460,7 @@
         }
         builder.append(string);
     }
+    // END Android-added: utility method to format an offset as a GMT offset string.
 
     /**
      * Returns the amount of time to be added to local standard time
diff --git a/ojluni/src/main/java/java/util/XMLUtils.java b/ojluni/src/main/java/java/util/XMLUtils.java
index b7133dc..8f061e5 100644
--- a/ojluni/src/main/java/java/util/XMLUtils.java
+++ b/ojluni/src/main/java/java/util/XMLUtils.java
@@ -92,7 +92,7 @@
     {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         dbf.setIgnoringElementContentWhitespace(true);
-        // Android-chanaged: We don't currently have a validating document builder.
+        // Android-changed: We don't currently have a validating document builder.
         // Revert this if the situation changes.
         //
         // dbf.setValidating(true);
diff --git a/ojluni/src/main/java/java/util/logging/Level.java b/ojluni/src/main/java/java/util/logging/Level.java
index afc7035..c03b171 100644
--- a/ojluni/src/main/java/java/util/logging/Level.java
+++ b/ojluni/src/main/java/java/util/logging/Level.java
@@ -262,7 +262,7 @@
     }
 
     private String computeLocalizedLevelName(Locale newLocale) {
-        // Android-change: Use Thread.currentThread().getContextClassLoader(),
+        // Android-changed: Use Thread.currentThread().getContextClassLoader(),
         // otherwise we might get a BootClassLoader.
         ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale,
                                                      Thread.currentThread().getContextClassLoader());
diff --git a/ojluni/src/main/java/java/util/logging/LoggingPermission.java b/ojluni/src/main/java/java/util/logging/LoggingPermission.java
index 23c5432..5cea7a5 100644
--- a/ojluni/src/main/java/java/util/logging/LoggingPermission.java
+++ b/ojluni/src/main/java/java/util/logging/LoggingPermission.java
@@ -26,6 +26,8 @@
 
 package java.util.logging;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/javax/crypto/Cipher.java b/ojluni/src/main/java/javax/crypto/Cipher.java
index c2a2183..e3c266f 100644
--- a/ojluni/src/main/java/javax/crypto/Cipher.java
+++ b/ojluni/src/main/java/javax/crypto/Cipher.java
@@ -44,9 +44,6 @@
 
 import java.nio.ByteBuffer;
 import java.nio.ReadOnlyBufferException;
-/* Android-removed: this debugging mechanism is not used in Android
-import sun.security.util.Debug;
-*/
 import sun.security.jca.*;
 
 /**
@@ -230,7 +227,11 @@
 
 public class Cipher {
 
-    /* Android-removed: this debugging mechanism is not used in Android
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Cipher");
+
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -835,7 +836,8 @@
 
         initialized = true;
         this.opmode = opmode;
-        /* Android-removed: this debugging mechanism is not used in Android
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
@@ -975,7 +977,8 @@
         initialized = true;
         this.opmode = opmode;
 
-        /* Android-removed: this debugging mechanism is not used in Android
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
@@ -1115,7 +1118,8 @@
         initialized = true;
         this.opmode = opmode;
 
-        /* Android-removed: this debugging mechanism is not used in Android
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
@@ -1301,7 +1305,8 @@
         initialized = true;
         this.opmode = opmode;
 
-        /* Android-removed: this debugging mechanism is not used in Android
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
@@ -2171,8 +2176,8 @@
      */
     public static final int getMaxAllowedKeyLength(String transformation)
             throws NoSuchAlgorithmException {
-        // Android-changed: Remove references to CryptoPermission and throw early
-        // if transformation == null or isn't valid.
+        // Android-changed: Remove references to CryptoPermission.
+        // Throw early if transformation == null or isn't valid.
         //
         // CryptoPermission cp = getConfiguredPermission(transformation);
         // return cp.getMaxAllowedKeyLength();
@@ -2204,8 +2209,8 @@
      */
     public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
             String transformation) throws NoSuchAlgorithmException {
-        // Android-changed: Remove references to CryptoPermission and throw early
-        // if transformation == null or isn't valid.
+        // Android-changed: Remove references to CryptoPermission.
+        // Throw early if transformation == null or isn't valid.
         //
         // CryptoPermission cp = getConfiguredPermission(transformation);
         // return cp.getAlgorithmParameterSpec();
diff --git a/ojluni/src/main/java/javax/crypto/CryptoAllPermission.java b/ojluni/src/main/java/javax/crypto/CryptoAllPermission.java
index 24268b8..8a973fc 100644
--- a/ojluni/src/main/java/javax/crypto/CryptoAllPermission.java
+++ b/ojluni/src/main/java/javax/crypto/CryptoAllPermission.java
@@ -25,6 +25,8 @@
 
 package javax.crypto;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/javax/crypto/CryptoPermission.java b/ojluni/src/main/java/javax/crypto/CryptoPermission.java
index ec09287..56973b6 100644
--- a/ojluni/src/main/java/javax/crypto/CryptoPermission.java
+++ b/ojluni/src/main/java/javax/crypto/CryptoPermission.java
@@ -28,6 +28,8 @@
 import java.security.*;
 import java.security.spec.AlgorithmParameterSpec;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/javax/crypto/CryptoPermissions.java b/ojluni/src/main/java/javax/crypto/CryptoPermissions.java
index 0e62b18..eef08b7 100644
--- a/ojluni/src/main/java/javax/crypto/CryptoPermissions.java
+++ b/ojluni/src/main/java/javax/crypto/CryptoPermissions.java
@@ -31,6 +31,8 @@
 import java.io.InputStream;
 import java.io.IOException;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/javax/crypto/CryptoPolicyParser.java b/ojluni/src/main/java/javax/crypto/CryptoPolicyParser.java
index a5a3818..10bdc55 100644
--- a/ojluni/src/main/java/javax/crypto/CryptoPolicyParser.java
+++ b/ojluni/src/main/java/javax/crypto/CryptoPolicyParser.java
@@ -29,6 +29,8 @@
 
 import java.security.GeneralSecurityException;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/javax/crypto/JceSecurity.java b/ojluni/src/main/java/javax/crypto/JceSecurity.java
index 073d827..4572627 100644
--- a/ojluni/src/main/java/javax/crypto/JceSecurity.java
+++ b/ojluni/src/main/java/javax/crypto/JceSecurity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,8 +64,14 @@
     private final static Map<Provider, Object> verifyingProviders =
             new IdentityHashMap<>();
 
-    // Set the default value. May be changed in the static initializer.
-    private static boolean isRestricted = true;
+    // Android-removed: JCE crypto strength restrictions are never in place on Android.
+    // private static final boolean isRestricted = true;
+
+    // Android-removed: This debugging mechanism is not used in Android.
+    /*
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Cipher");
+    */
 
     /*
      * Don't let anyone instantiate this.
@@ -73,7 +79,7 @@
     private JceSecurity() {
     }
 
-    // BEGIN Android-changed
+    // BEGIN Android-removed: JCE crypto strength restrictions are never in place on Android.
     /*
     static {
         try {
@@ -93,7 +99,7 @@
         }
     }
     */
-    // END Android-changed
+    // END Android-removed: JCE crypto strength restrictions are never in place on Android.
 
     static Instance getInstance(String type, Class<?> clazz, String algorithm,
             String provider) throws NoSuchAlgorithmException,
@@ -201,10 +207,10 @@
 
     // return whether this provider is properly signed and can be used by JCE
     static boolean canUseProvider(Provider p) {
-        // BEGIN Android-changed
+        // BEGIN Android-changed: All providers are available.
         // return getVerificationResult(p) == null;
         return true;
-        // END Android-changed
+        // END Android-changed: All providers are available.
     }
 
     // dummy object to represent null
@@ -212,7 +218,7 @@
 
     static {
         try {
-            NULL_URL = new URL("http://null.sun.com/");
+            NULL_URL = new URL("http://null.oracle.com/");
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -247,14 +253,71 @@
         }
     }
 
+    // BEGIN Android-removed: JCE crypto strength restrictions are never in place on Android.
+    /*
+     * This is called from within an doPrivileged block.
+     *
+     * Following logic is used to decide what policy files are selected.
+     *
+     * If the new Security property (crypto.policy) is set in the
+     * java.security file, or has been set dynamically using the
+     * Security.setProperty() call before the JCE framework has
+     * been initialized, that setting will be used.
+     * Remember - this property is not defined by default. A conscious
+     * user edit or an application call is required.
+     *
+     * Otherwise, if user has policy jar files installed in the legacy
+     * jre/lib/security/ directory, the JDK will honor whatever
+     * setting is set by those policy files. (legacy/current behavior)
+     *
+     * If none of the above 2 conditions are met, the JDK will default
+     * to using the limited crypto policy files found in the
+     * jre/lib/security/policy/limited/ directory
+     *
     private static void setupJurisdictionPolicies() throws Exception {
-        String javaHomeDir = System.getProperty("java.home");
-        String sep = File.separator;
-        String pathToPolicyJar = javaHomeDir + sep + "lib" + sep +
-            "security" + sep;
+        // Sanity check the crypto.policy Security property.  Single
+        // directory entry, no pseudo-directories (".", "..", leading/trailing
+        // path separators). normalize()/getParent() will help later.
+        String javaHomeProperty = System.getProperty("java.home");
+        String cryptoPolicyProperty = Security.getProperty("crypto.policy");
+        Path cpPath = (cryptoPolicyProperty == null) ? null :
+                Paths.get(cryptoPolicyProperty);
 
-        File exportJar = new File(pathToPolicyJar, "US_export_policy.jar");
-        File importJar = new File(pathToPolicyJar, "local_policy.jar");
+        if ((cpPath != null) && ((cpPath.getNameCount() != 1) ||
+                (cpPath.compareTo(cpPath.getFileName())) != 0)) {
+            throw new SecurityException(
+                    "Invalid policy directory name format: " +
+                            cryptoPolicyProperty);
+        }
+
+        if (cpPath == null) {
+            // Security property is not set, use default path
+            cpPath = Paths.get(javaHomeProperty, "lib", "security");
+        } else {
+            // populate with java.home
+            cpPath = Paths.get(javaHomeProperty, "lib", "security",
+                    "policy", cryptoPolicyProperty);
+        }
+
+        if (debug != null) {
+            debug.println("crypto policy directory: " + cpPath);
+        }
+
+        File exportJar = new File(cpPath.toFile(),"US_export_policy.jar");
+        File importJar = new File(cpPath.toFile(),"local_policy.jar");
+
+        if (cryptoPolicyProperty == null && (!exportJar.exists() ||
+                !importJar.exists())) {
+            // Compatibility set up. If crypto.policy is not defined.
+            // check to see if legacy jars exist in lib directory. If
+            // they don't exist, we default to limited policy mode.
+            cpPath = Paths.get(
+                    javaHomeProperty, "lib", "security", "policy", "limited");
+            // point to the new jar files in limited directory
+            exportJar = new File(cpPath.toFile(),"US_export_policy.jar");
+            importJar = new File(cpPath.toFile(),"local_policy.jar");
+        }
+
         URL jceCipherURL = ClassLoader.getSystemResource
                 ("javax/crypto/Cipher.class");
 
@@ -287,6 +350,8 @@
             exemptPolicy = exemptExport.getMinimum(exemptImport);
         }
     }
+    */
+    // END Android-removed: JCE crypto strength restrictions are never in place on Android.
 
     /**
      * Load the policies from the specified file. Also checks that the
@@ -337,7 +402,8 @@
         return exemptPolicy;
     }
 
-    static boolean isRestricted() {
-        return isRestricted;
-    }
+    // Android-removed: JCE crypto strength restrictions are never in place on Android.
+    // static boolean isRestricted() {
+    //     return isRestricted;
+    // }
 }
diff --git a/ojluni/src/main/java/javax/crypto/JceSecurityManager.java b/ojluni/src/main/java/javax/crypto/JceSecurityManager.java
index 38d9f19..aafaa58 100644
--- a/ojluni/src/main/java/javax/crypto/JceSecurityManager.java
+++ b/ojluni/src/main/java/javax/crypto/JceSecurityManager.java
@@ -25,6 +25,8 @@
 
 package javax.crypto;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/javax/crypto/KeyAgreement.java b/ojluni/src/main/java/javax/crypto/KeyAgreement.java
index 8a0b1c1..ffa18b1 100644
--- a/ojluni/src/main/java/javax/crypto/KeyAgreement.java
+++ b/ojluni/src/main/java/javax/crypto/KeyAgreement.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,9 +32,6 @@
 import java.security.Provider.Service;
 import java.security.spec.*;
 
-/* Android-removed: this debugging mechanism is not used in Android.
-import sun.security.util.Debug;
-*/
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
 
@@ -91,7 +88,11 @@
 
 public class KeyAgreement {
 
-    /* Android-removed: this debugging mechanism is not used in Android.
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
+    private static final Debug debug =
+                        Debug.getInstance("jca", "KeyAgreement");
+
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -107,6 +108,23 @@
     // The name of the key agreement algorithm.
     private final String algorithm;
 
+    // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
+    // When only the algorithm is specified, we want to allow the KeyAgreement provider for that
+    // algorithm to change if multiple providers exist and they support different subsets of
+    // keys.  To that end, we don't hold an iterator and exhaust it when we need to choose
+    // a provider like the upstream implementation, we reestablish the list of providers
+    // each time.
+    /*
+    // next service to try in provider selection
+    // null once provider is selected
+    private Service firstService;
+
+    // remaining services to try in provider selection
+    // null once provider is selected
+    private Iterator<Service> serviceIterator;
+    */
+    // END Android-removed: Redo the provider selection logic to allow reselecting provider.
+
     private final Object lock;
 
     /**
@@ -124,6 +142,7 @@
         lock = null;
     }
 
+    // Android-changed: Remove Service and Iterator from constructor args.
     private KeyAgreement(String algorithm) {
         this.algorithm = algorithm;
         lock = new Object();
@@ -184,6 +203,8 @@
             if (JceSecurity.canUseProvider(s.getProvider()) == false) {
                 continue;
             }
+            // Android-changed: Remove Service and Iterator from constructor args.
+            // return new KeyAgreement(s, t, algorithm);
             return new KeyAgreement(algorithm);
         }
         throw new NoSuchAlgorithmException
@@ -293,7 +314,8 @@
             if (spi != null) {
                 return;
             }
-            /* Android-removed: this debugging mechanism is not used in Android.
+            // Android-removed: this debugging mechanism is not used in Android.
+            /*
             if (debug != null) {
                 int w = --warnCount;
                 if (w >= 0) {
@@ -308,6 +330,7 @@
             }
             */
             Exception lastException = null;
+            // Android-changed: Provider selection; loop over a new list each time.
             for (Service s : GetInstance.getServices("KeyAgreement", algorithm)) {
                 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
                     continue;
@@ -319,7 +342,12 @@
                     }
                     spi = (KeyAgreementSpi)obj;
                     provider = s.getProvider();
+                    // Android-removed: Provider selection; loop over a new list each time.
+                    /*
                     // not needed any more
+                    firstService = null;
+                    serviceIterator = null;
+                    */
                     return;
                 } catch (Exception e) {
                     lastException = e;
@@ -351,11 +379,14 @@
             AlgorithmParameterSpec params, SecureRandom random)
             throws InvalidKeyException, InvalidAlgorithmParameterException {
         synchronized (lock) {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (spi != null) {
             if (spi != null && key == null) {
                 implInit(spi, initType, key, params, random);
                 return;
             }
             Exception lastException = null;
+            // Android-changed: Provider selection; loop over a new list each time.
             for (Service s : GetInstance.getServices("KeyAgreement", algorithm)) {
                 // if provider says it does not support this key, ignore it
                 if (s.supportsParameter(key) == false) {
@@ -369,6 +400,11 @@
                     implInit(spi, initType, key, params, random);
                     provider = s.getProvider();
                     this.spi = spi;
+                    // Android-removed: Provider selection; loop over a new list each time.
+                    /*
+                    firstService = null;
+                    serviceIterator = null;
+                    */
                     return;
                 } catch (Exception e) {
                     // NoSuchAlgorithmException from newInstance()
@@ -452,6 +488,8 @@
      */
     public final void init(Key key, SecureRandom random)
             throws InvalidKeyException {
+        // Android-changed: Use the currently-selected provider only if no key was provided.
+        // if (spi != null) {
         if (spi != null && (key == null || lock == null)) {
             spi.engineInit(key, random);
         } else {
@@ -463,7 +501,8 @@
             }
         }
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
                 this.provider.getName());
@@ -526,7 +565,8 @@
             chooseProvider(I_PARAMS, key, params, random);
         }
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
                 this.provider.getName());
diff --git a/ojluni/src/main/java/javax/crypto/KeyGenerator.java b/ojluni/src/main/java/javax/crypto/KeyGenerator.java
index 8a54e5c..5dfde97 100644
--- a/ojluni/src/main/java/javax/crypto/KeyGenerator.java
+++ b/ojluni/src/main/java/javax/crypto/KeyGenerator.java
@@ -33,9 +33,6 @@
 
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
-/* Android-removed: this debugging mechanism is not used in Android.
-import sun.security.util.Debug;
-*/
 
 /**
  * This class provides the functionality of a secret (symmetric) key generator.
@@ -167,7 +164,8 @@
 
 public class KeyGenerator {
 
-    /* Android-removed: this debugging mechanism is not used in Android.
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -212,7 +210,8 @@
         this.provider = provider;
         this.algorithm = algorithm;
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
                 this.provider.getName());
@@ -232,7 +231,8 @@
                 (algorithm + " KeyGenerator not available");
         }
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
                 this.provider.getName());
diff --git a/ojluni/src/main/java/javax/crypto/Mac.java b/ojluni/src/main/java/javax/crypto/Mac.java
index 2315db7..c3d99fb 100644
--- a/ojluni/src/main/java/javax/crypto/Mac.java
+++ b/ojluni/src/main/java/javax/crypto/Mac.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,9 +34,6 @@
 
 import java.nio.ByteBuffer;
 
-/* Android-removed: this debugging mechanism is not used in Android.
-import sun.security.util.Debug;
-*/
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
 
@@ -156,7 +153,11 @@
 
 public class Mac implements Cloneable {
 
-    /* Android-removed: this debugging mechanism is not used in Android.
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Mac");
+
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -175,6 +176,23 @@
     // Has this object been initialized?
     private boolean initialized = false;
 
+    // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
+    // When only the algorithm is specified, we want to allow the Mac provider for that
+    // algorithm to change if multiple providers exist and they support different subsets of
+    // keys.  To that end, we don't hold an iterator and exhaust it when we need to choose
+    // a provider like the upstream implementation, we reestablish the list of providers
+    // each time.
+    /*
+    // next service to try in provider selection
+    // null once provider is selected
+    private Service firstService;
+
+    // remaining services to try in provider selection
+    // null once provider is selected
+    private Iterator<Service> serviceIterator;
+    */
+    // END Android-removed: Redo the provider selection logic to allow reselecting provider.
+
     private final Object lock;
 
     /**
@@ -191,6 +209,7 @@
         lock = null;
     }
 
+    // Android-changed: Remove Service and Iterator from constructor args.
     private Mac(String algorithm) {
         this.algorithm = algorithm;
         lock = new Object();
@@ -246,6 +265,8 @@
             if (JceSecurity.canUseProvider(s.getProvider()) == false) {
                 continue;
             }
+            // Android-changed: Remove Service and Iterator from constructor args.
+            // return new Mac(s, t, algorithm);
             return new Mac(algorithm);
         }
         throw new NoSuchAlgorithmException
@@ -337,6 +358,8 @@
      * is not the first method called.
      */
     void chooseFirstProvider() {
+        // Android-changed: Check if lock is null rather than removed serviceIterator field.
+        // if ((spi != null) || (serviceIterator == null)) {
         if (spi != null || lock == null) {
             return;
         }
@@ -344,7 +367,8 @@
             if (spi != null) {
                 return;
             }
-            /* Android-removed: this debugging mechanism is not used in Android.
+            // Android-removed: this debugging mechanism is not used in Android.
+            /*
             if (debug != null) {
                 int w = --warnCount;
                 if (w >= 0) {
@@ -359,6 +383,7 @@
             }
             */
             Exception lastException = null;
+            // Android-changed: Provider selection; loop over a new list each time.
             for (Service s : GetInstance.getServices("Mac", algorithm)) {
                 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
                     continue;
@@ -370,6 +395,12 @@
                     }
                     spi = (MacSpi)obj;
                     provider = s.getProvider();
+                    // Android-removed: Provider selection; loop over a new list each time.
+                    /*
+                    // not needed any more
+                    firstService = null;
+                    serviceIterator = null;
+                    */
                     return;
                 } catch (NoSuchAlgorithmException e) {
                     lastException = e;
@@ -387,11 +418,14 @@
     private void chooseProvider(Key key, AlgorithmParameterSpec params)
             throws InvalidKeyException, InvalidAlgorithmParameterException {
         synchronized (lock) {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (spi != null) {
             if (spi != null && (key == null || lock == null)) {
                 spi.engineInit(key, params);
                 return;
             }
             Exception lastException = null;
+            // Android-changed: Provider selection; loop over a new list each time.
             for (Service s : GetInstance.getServices("Mac", algorithm)) {
                 // if provider says it does not support this key, ignore it
                 if (s.supportsParameter(key) == false) {
@@ -405,6 +439,11 @@
                     spi.engineInit(key, params);
                     provider = s.getProvider();
                     this.spi = spi;
+                    // Android-removed: Provider selection; loop over a new list each time.
+                    /*
+                    firstService = null;
+                    serviceIterator = null;
+                    */
                     return;
                 } catch (Exception e) {
                     // NoSuchAlgorithmException from newInstance()
@@ -462,6 +501,8 @@
      */
     public final void init(Key key) throws InvalidKeyException {
         try {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (spi != null) {
             if (spi != null && (key == null || lock == null)) {
                 spi.engineInit(key, null);
             } else {
@@ -472,7 +513,8 @@
         }
         initialized = true;
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Mac." + algorithm + " algorithm from: " +
                 this.provider.getName());
@@ -494,6 +536,8 @@
      */
     public final void init(Key key, AlgorithmParameterSpec params)
             throws InvalidKeyException, InvalidAlgorithmParameterException {
+        // Android-changed: Use the currently-selected provider only if no key was provided.
+        // if (spi != null) {
         if (spi != null && (key == null || lock == null)) {
             spi.engineInit(key, params);
         } else {
@@ -501,7 +545,8 @@
         }
         initialized = true;
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Mac." + algorithm + " algorithm from: " +
                 this.provider.getName());
@@ -727,6 +772,7 @@
         return that;
     }
 
+    // BEGIN Android-added: Allow access to the current SPI for testing purposes.
     /**
      * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is
      * backing this {@code Mac}.
@@ -736,4 +782,5 @@
     public MacSpi getCurrentSpi() {
         return spi;
     }
+    // END Android-added: Allow access to the current SPI for testing purposes.
 }
diff --git a/ojluni/src/main/java/javax/net/SocketFactory.java b/ojluni/src/main/java/javax/net/SocketFactory.java
index 2bcfac3..3c89371 100644
--- a/ojluni/src/main/java/javax/net/SocketFactory.java
+++ b/ojluni/src/main/java/javax/net/SocketFactory.java
@@ -104,6 +104,7 @@
         return theFactory;
     }
 
+    // Android-added: Added method for testing default socket factory.
     /** @hide Visible for testing only */
     public static void setDefault(SocketFactory factory) {
         synchronized (SocketFactory.class) {
diff --git a/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java b/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java
index 9660643..ec4254a 100644
--- a/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java
+++ b/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java
@@ -178,6 +178,10 @@
         }
     }
 
+    // BEGIN Android-changed: Use lazily-created OkHttp hostname verifier
+    // The RI default hostname verifier is a static member of the class, which means
+    // it's created when the class is initialized.  As well, its default verifier
+    // just fails all verification attempts, whereas we use OkHttp's verifier.
     /*
      * Holds the default instance so class preloading doesn't create an instance of
      * it.
@@ -207,6 +211,7 @@
      * The <code>hostnameVerifier</code> for this object.
      */
     protected HostnameVerifier hostnameVerifier;
+    // END Android-changed: Use lazily-created OkHttp hostname verifier
 
     /**
      * Sets the default <code>HostnameVerifier</code> inherited by a
@@ -279,6 +284,7 @@
      * @see #setDefaultHostnameVerifier(HostnameVerifier)
      */
     public HostnameVerifier getHostnameVerifier() {
+        // Android-added: Use the default verifier if none is set
         if (hostnameVerifier == null) {
             hostnameVerifier = NoPreloadHolder.defaultHostnameVerifier;
         }
diff --git a/ojluni/src/main/java/javax/net/ssl/SNIServerName.java b/ojluni/src/main/java/javax/net/ssl/SNIServerName.java
index c5bb253..1ef9d05 100644
--- a/ojluni/src/main/java/javax/net/ssl/SNIServerName.java
+++ b/ojluni/src/main/java/javax/net/ssl/SNIServerName.java
@@ -210,3 +210,4 @@
         return sb.toString();
     }
 }
+
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLContext.java b/ojluni/src/main/java/javax/net/ssl/SSLContext.java
index 71cfc23..4105282 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLContext.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLContext.java
@@ -178,7 +178,7 @@
      * @return the new <code>SSLContext</code> object.
      *
      * @exception NoSuchAlgorithmException if no Provider supports a
-     *          TrustManagerFactorySpi implementation for the
+     *          SSLContextSpi implementation for the
      *          specified protocol.
      * @exception NullPointerException if protocol is null.
      *
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLEngine.java b/ojluni/src/main/java/javax/net/ssl/SSLEngine.java
index 35481e4..a513c49 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLEngine.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLEngine.java
@@ -329,6 +329,7 @@
  * is saved.  All future delegated tasks will be processed using this
  * context:  that is, all access control decisions will be made using the
  * context captured at engine creation.
+ *
  * <HR>
  *
  * <B>Concurrency Notes</B>:
@@ -1183,7 +1184,7 @@
      * If this <code>SSLEngine</code> has not yet started its initial
      * handshake, this method will automatically start the handshake.
      * <P>
-     * This method will attempt to produce one SSL/TLS packet, and will
+     * This method will attempt to produce SSL/TLS records, and will
      * consume as much source data as possible, but will never consume
      * more than the sum of the bytes remaining in each buffer.  Each
      * <code>ByteBuffer</code>'s position is updated to reflect the
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLPermission.java b/ojluni/src/main/java/javax/net/ssl/SSLPermission.java
index 0f6b5db..a23e1ce 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLPermission.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLPermission.java
@@ -27,6 +27,8 @@
 
 import java.security.*;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLServerSocketFactory.java b/ojluni/src/main/java/javax/net/ssl/SSLServerSocketFactory.java
index a480c60..2db63bb 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLServerSocketFactory.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLServerSocketFactory.java
@@ -45,8 +45,16 @@
  */
 public abstract class SSLServerSocketFactory extends ServerSocketFactory
 {
+    // Android-changed: Renamed field.
+    // Some apps rely on changing this field via reflection, so we can't change the name
+    // without introducing app compatibility problems.  See http://b/62248930.
     private static SSLServerSocketFactory defaultServerSocketFactory;
 
+    // Android-changed: Check Security.getVersion() on each update.
+    // If the set of providers or other such things changes, it may change the default
+    // factory, so we track the version returned from Security.getVersion() instead of
+    // only having a flag that says if we've ever initialized the default.
+    // private static boolean propertyChecked;
     private static int lastVersion = -1;
 
     private static void log(String msg) {
@@ -77,10 +85,7 @@
      * @see SSLContext#getDefault
      */
     public static synchronized ServerSocketFactory getDefault() {
-        // Android-changed: Use security version instead of propertyChecked.
-        //
-        // We use the same lookup logic in SSLSocketFactory.getDefault(). Any changes
-        // made here must be mirrored in that class.
+        // Android-changed: Check Security.getVersion() on each update.
         if (defaultServerSocketFactory != null && lastVersion == Security.getVersion()) {
             return defaultServerSocketFactory;
         }
@@ -90,8 +95,9 @@
         defaultServerSocketFactory = null;
 
         String clsName = SSLSocketFactory.getSecurityProperty
-                ("ssl.ServerSocketFactory.provider");
+                                    ("ssl.ServerSocketFactory.provider");
         if (clsName != null) {
+            // Android-changed: Check if we already have an instance of the default factory class.
             // The instance for the default socket factory is checked for updates quite
             // often (for instance, every time a security provider is added). Which leads
             // to unnecessary overload and excessive error messages in case of class-loading
@@ -101,10 +107,9 @@
                 defaultServerSocketFactory = previousDefaultServerSocketFactory;
                 return defaultServerSocketFactory;
             }
-            Class cls = null;
             log("setting up default SSLServerSocketFactory");
             try {
-                log("setting up default SSLServerSocketFactory");
+                Class<?> cls = null;
                 try {
                     cls = Class.forName(clsName);
                 } catch (ClassNotFoundException e) {
@@ -115,37 +120,33 @@
                     }
 
                     if (cl != null) {
+                        // Android-changed: Use Class.forName() so the class gets initialized.
                         cls = Class.forName(clsName, true, cl);
                     }
                 }
                 log("class " + clsName + " is loaded");
-                SSLServerSocketFactory fac = (SSLServerSocketFactory) cls.newInstance();
+                SSLServerSocketFactory fac = (SSLServerSocketFactory)cls.newInstance();
                 log("instantiated an instance of class " + clsName);
                 defaultServerSocketFactory = fac;
-                if (defaultServerSocketFactory != null) {
-                    return defaultServerSocketFactory;
-                }
+                return fac;
             } catch (Exception e) {
                 log("SSLServerSocketFactory instantiation failed: " + e);
-                // Android-changed: Fallback to the default SSLContext if an exception
-                // is thrown during the initialization of ssl.ServerSocketFactory.provider.
+                // Android-changed: Fallback to the default SSLContext on exception.
             }
         }
 
         try {
+            // Android-changed: Allow for {@code null} SSLContext.getDefault.
             SSLContext context = SSLContext.getDefault();
             if (context != null) {
                 defaultServerSocketFactory = context.getServerSocketFactory();
+            } else {
+                defaultServerSocketFactory = new DefaultSSLServerSocketFactory(new IllegalStateException("No factory found."));
             }
+            return defaultServerSocketFactory;
         } catch (NoSuchAlgorithmException e) {
+            return new DefaultSSLServerSocketFactory(e);
         }
-
-        if (defaultServerSocketFactory == null) {
-            defaultServerSocketFactory = new DefaultSSLServerSocketFactory(
-                    new IllegalStateException("No ServerSocketFactory implementation found"));
-        }
-
-        return defaultServerSocketFactory;
     }
 
     /**
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLSocketFactory.java b/ojluni/src/main/java/javax/net/ssl/SSLSocketFactory.java
index f1d7057..93b5dc7 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLSocketFactory.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLSocketFactory.java
@@ -30,6 +30,7 @@
 import java.net.*;
 import javax.net.SocketFactory;
 import java.io.IOException;
+import java.io.InputStream;
 import java.security.*;
 import java.util.Locale;
 
@@ -44,8 +45,16 @@
  */
 public abstract class SSLSocketFactory extends SocketFactory
 {
+    // Android-changed: Renamed field.
+    // Some apps rely on changing this field via reflection, so we can't change the name
+    // without introducing app compatibility problems.  See http://b/62248930.
     private static SSLSocketFactory defaultSocketFactory;
 
+    // Android-changed: Check Security.getVersion() on each update.
+    // If the set of providers or other such things changes, it may change the default
+    // factory, so we track the version returned from Security.getVersion() instead of
+    // only having a flag that says if we've ever initialized the default.
+    // private static boolean propertyChecked;
     private static int lastVersion = -1;
 
     static final boolean DEBUG;
@@ -86,7 +95,7 @@
      * @see SSLContext#getDefault
      */
     public static synchronized SocketFactory getDefault() {
-        // Android-changed: Use security version instead of propertyChecked.
+        // Android-changed: Check Security.getVersion() on each update.
         if (defaultSocketFactory != null && lastVersion == Security.getVersion()) {
             return defaultSocketFactory;
         }
@@ -98,6 +107,7 @@
         String clsName = getSecurityProperty("ssl.SocketFactory.provider");
 
         if (clsName != null) {
+            // Android-changed: Check if we already have an instance of the default factory class.
             // The instance for the default socket factory is checked for updates quite
             // often (for instance, every time a security provider is added). Which leads
             // to unnecessary overload and excessive error messages in case of class-loading
@@ -109,49 +119,49 @@
             }
             log("setting up default SSLSocketFactory");
             try {
-                Class cls = null;
+                Class<?> cls = null;
                 try {
                     cls = Class.forName(clsName);
                 } catch (ClassNotFoundException e) {
-                    // Android-changed; Try the contextClassLoader first.
+                    // Android-changed: Try the contextClassLoader first.
                     ClassLoader cl = Thread.currentThread().getContextClassLoader();
                     if (cl == null) {
                         cl = ClassLoader.getSystemClassLoader();
                     }
 
                     if (cl != null) {
+                        // Android-changed: Use Class.forName() so the class gets initialized.
                         cls = Class.forName(clsName, true, cl);
                     }
                 }
                 log("class " + clsName + " is loaded");
-                defaultSocketFactory = (SSLSocketFactory)cls.newInstance();
+                SSLSocketFactory fac = (SSLSocketFactory)cls.newInstance();
                 log("instantiated an instance of class " + clsName);
-                if (defaultSocketFactory != null) {
-                    return defaultSocketFactory;
-                }
+                defaultSocketFactory = fac;
+                return fac;
             } catch (Exception e) {
                 log("SSLSocketFactory instantiation failed: " + e.toString());
+                // Android-changed: Fallback to the default SSLContext on exception.
             }
         }
 
-        // Android-changed: Allow for {@code null} SSLContext.getDefault.
         try {
+            // Android-changed: Allow for {@code null} SSLContext.getDefault.
             SSLContext context = SSLContext.getDefault();
             if (context != null) {
                 defaultSocketFactory = context.getSocketFactory();
+            } else {
+                defaultSocketFactory = new DefaultSSLSocketFactory(new IllegalStateException("No factory found."));
             }
+            return defaultSocketFactory;
         } catch (NoSuchAlgorithmException e) {
+            return new DefaultSSLSocketFactory(e);
         }
-
-        if (defaultSocketFactory == null) {
-            defaultSocketFactory = new DefaultSSLSocketFactory(new IllegalStateException("No factory found."));
-        }
-
-        return defaultSocketFactory;
     }
 
     static String getSecurityProperty(final String name) {
         return AccessController.doPrivileged(new PrivilegedAction<String>() {
+            @Override
             public String run() {
                 String s = java.security.Security.getProperty(name);
                 if (s != null) {
@@ -207,6 +217,56 @@
      */
     public abstract Socket createSocket(Socket s, String host,
             int port, boolean autoClose) throws IOException;
+
+    /**
+     * Creates a server mode {@link Socket} layered over an
+     * existing connected socket, and is able to read data which has
+     * already been consumed/removed from the {@link Socket}'s
+     * underlying {@link InputStream}.
+     * <p>
+     * This method can be used by a server application that needs to
+     * observe the inbound data but still create valid SSL/TLS
+     * connections: for example, inspection of Server Name Indication
+     * (SNI) extensions (See section 3 of <A
+     * HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions
+     * (RFC6066)</A>).  Data that has been already removed from the
+     * underlying {@link InputStream} should be loaded into the
+     * {@code consumed} stream before this method is called, perhaps
+     * using a {@link java.io.ByteArrayInputStream}.  When this
+     * {@link Socket} begins handshaking, it will read all of the data in
+     * {@code consumed} until it reaches {@code EOF}, then all further
+     * data is read from the underlying {@link InputStream} as
+     * usual.
+     * <p>
+     * The returned socket is configured using the socket options
+     * established for this factory, and is set to use server mode when
+     * handshaking (see {@link SSLSocket#setUseClientMode(boolean)}).
+     *
+     * @param  s
+     *         the existing socket
+     * @param  consumed
+     *         the consumed inbound network data that has already been
+     *         removed from the existing {@link Socket}
+     *         {@link InputStream}.  This parameter may be
+     *         {@code null} if no data has been removed.
+     * @param  autoClose close the underlying socket when this socket is closed.
+     *
+     * @return the {@link Socket} compliant with the socket options
+     *         established for this factory
+     *
+     * @throws IOException if an I/O error occurs when creating the socket
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation
+     * @throws NullPointerException if {@code s} is {@code null}
+     *
+     * @since 1.8
+     *
+     * @hide
+     */
+    public Socket createSocket(Socket s, InputStream consumed,
+            boolean autoClose) throws IOException {
+        throw new UnsupportedOperationException();
+    }
 }
 
 
diff --git a/ojluni/src/main/java/javax/security/auth/AuthPermission.java b/ojluni/src/main/java/javax/security/auth/AuthPermission.java
index 651e9a3..71c3aaf 100644
--- a/ojluni/src/main/java/javax/security/auth/AuthPermission.java
+++ b/ojluni/src/main/java/javax/security/auth/AuthPermission.java
@@ -25,6 +25,8 @@
 
 package javax.security.auth;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/javax/security/auth/PrivateCredentialPermission.java b/ojluni/src/main/java/javax/security/auth/PrivateCredentialPermission.java
index ca52a1b2..9733932 100644
--- a/ojluni/src/main/java/javax/security/auth/PrivateCredentialPermission.java
+++ b/ojluni/src/main/java/javax/security/auth/PrivateCredentialPermission.java
@@ -29,6 +29,8 @@
 import java.security.Permission;
 import java.security.Principal;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/javax/security/auth/SubjectDomainCombiner.java b/ojluni/src/main/java/javax/security/auth/SubjectDomainCombiner.java
index 8e07d4b..868ed5f 100644
--- a/ojluni/src/main/java/javax/security/auth/SubjectDomainCombiner.java
+++ b/ojluni/src/main/java/javax/security/auth/SubjectDomainCombiner.java
@@ -27,6 +27,8 @@
 
 import java.security.ProtectionDomain;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/jdk/net/NetworkPermission.java b/ojluni/src/main/java/jdk/net/NetworkPermission.java
index 420c74f..96d7a8e 100644
--- a/ojluni/src/main/java/jdk/net/NetworkPermission.java
+++ b/ojluni/src/main/java/jdk/net/NetworkPermission.java
@@ -27,6 +27,8 @@
 
 import java.security.BasicPermission;
 
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
 /**
  * Legacy security code; do not use.
  */
diff --git a/ojluni/src/main/java/jdk/net/package-info.java b/ojluni/src/main/java/jdk/net/package-info.java
deleted file mode 100644
index b05d543..0000000
--- a/ojluni/src/main/java/jdk/net/package-info.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * Platform specific socket options for the {@code java.net} and {@code java.nio.channels}
- * socket classes.
- */
-
-@jdk.Exported
-package jdk.net;
diff --git a/ojluni/src/main/java/sun/misc/BASE64Decoder.java b/ojluni/src/main/java/sun/misc/BASE64Decoder.java
index 63f1228..e65a1d2 100644
--- a/ojluni/src/main/java/sun/misc/BASE64Decoder.java
+++ b/ojluni/src/main/java/sun/misc/BASE64Decoder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2000, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -102,6 +102,7 @@
     /**
      * Decode one BASE64 atom into 1, 2, or 3 bytes of data.
      */
+    @SuppressWarnings("fallthrough")
     protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int rem)
         throws java.io.IOException
     {
diff --git a/ojluni/src/main/java/sun/misc/CEFormatException.java b/ojluni/src/main/java/sun/misc/CEFormatException.java
index 974a55c..6d53fa2 100644
--- a/ojluni/src/main/java/sun/misc/CEFormatException.java
+++ b/ojluni/src/main/java/sun/misc/CEFormatException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,9 @@
 import java.io.IOException;
 
 public class CEFormatException extends IOException {
-        public CEFormatException(String s) {
-                super(s);
-        }
+    static final long serialVersionUID = -7139121221067081482L;
+    public CEFormatException(String s) {
+        super(s);
+    }
 }
+
diff --git a/ojluni/src/main/java/sun/misc/CEStreamExhausted.java b/ojluni/src/main/java/sun/misc/CEStreamExhausted.java
index 28e0ffe..fb2054e 100644
--- a/ojluni/src/main/java/sun/misc/CEStreamExhausted.java
+++ b/ojluni/src/main/java/sun/misc/CEStreamExhausted.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,4 +27,7 @@
 import java.io.IOException;
 
 /** This exception is thrown when EOF is reached */
-public class CEStreamExhausted extends IOException { };
+public class CEStreamExhausted extends IOException {
+    static final long serialVersionUID = -5889118049525891904L;
+}
+
diff --git a/ojluni/src/main/java/sun/misc/CharacterDecoder.java b/ojluni/src/main/java/sun/misc/CharacterDecoder.java
index 76b04ea..728e7602 100644
--- a/ojluni/src/main/java/sun/misc/CharacterDecoder.java
+++ b/ojluni/src/main/java/sun/misc/CharacterDecoder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -145,7 +145,7 @@
      * Decode the text from the InputStream and write the decoded
      * octets to the OutputStream. This method runs until the stream
      * is exhausted.
-     * @exception CEFormatException An error has occured while decoding
+     * @exception CEFormatException An error has occurred while decoding
      * @exception CEStreamExhausted The input stream is unexpectedly out of data
      */
     public void decodeBuffer(InputStream aStream, OutputStream bStream) throws IOException {
@@ -181,7 +181,7 @@
     /**
      * Alternate decode interface that takes a String containing the encoded
      * buffer and returns a byte array containing the data.
-     * @exception CEFormatException An error has occured while decoding
+     * @exception CEFormatException An error has occurred while decoding
      */
     public byte decodeBuffer(String inputString)[] throws IOException {
         byte    inputBuffer[] = new byte[inputString.length()];
diff --git a/ojluni/src/main/java/sun/misc/Cleaner.java b/ojluni/src/main/java/sun/misc/Cleaner.java
index f23764e..5e92f35 100644
--- a/ojluni/src/main/java/sun/misc/Cleaner.java
+++ b/ojluni/src/main/java/sun/misc/Cleaner.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,14 +57,14 @@
  */
 
 public class Cleaner
-    extends PhantomReference
+    extends PhantomReference<Object>
 {
 
     // Dummy reference queue, needed because the PhantomReference constructor
     // insists that we pass a queue.  Nothing will ever be placed on this queue
     // since the reference handler invokes cleaners explicitly.
     //
-    private static final ReferenceQueue dummyQueue = new ReferenceQueue();
+    private static final ReferenceQueue<Object> dummyQueue = new ReferenceQueue<>();
 
     // Doubly-linked list of live cleaners, which prevents the cleaners
     // themselves from being GC'd before their referents
@@ -119,6 +119,7 @@
     /**
      * Creates a new cleaner.
      *
+     * @param  ob the referent object to be cleaned
      * @param  thunk
      *         The cleanup code to be run when the cleaner is invoked.  The
      *         cleanup code is run directly from the reference-handler thread,
diff --git a/ojluni/src/main/java/sun/misc/CompoundEnumeration.java b/ojluni/src/main/java/sun/misc/CompoundEnumeration.java
index 69de7f8..a89ec5f 100644
--- a/ojluni/src/main/java/sun/misc/CompoundEnumeration.java
+++ b/ojluni/src/main/java/sun/misc/CompoundEnumeration.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,10 +33,10 @@
  * enumerations.
  */
 public class CompoundEnumeration<E> implements Enumeration<E> {
-    private Enumeration[] enums;
+    private Enumeration<E>[] enums;
     private int index = 0;
 
-    public CompoundEnumeration(Enumeration[] enums) {
+    public CompoundEnumeration(Enumeration<E>[] enums) {
         this.enums = enums;
     }
 
@@ -58,6 +58,6 @@
         if (!next()) {
             throw new NoSuchElementException();
         }
-        return (E)enums[index].nextElement();
+        return enums[index].nextElement();
     }
 }
diff --git a/ojluni/src/main/java/sun/misc/FDBigInt.java b/ojluni/src/main/java/sun/misc/FDBigInt.java
deleted file mode 100644
index 85b5b35..0000000
--- a/ojluni/src/main/java/sun/misc/FDBigInt.java
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-/*
- * A really, really simple bigint package
- * tailored to the needs of floating base conversion.
- */
-public class FDBigInt {
-    int nWords; // number of words used
-    int data[]; // value: data[0] is least significant
-
-
-    public FDBigInt( int v ){
-        nWords = 1;
-        data = new int[1];
-        data[0] = v;
-    }
-
-    public FDBigInt( long v ){
-        data = new int[2];
-        data[0] = (int)v;
-        data[1] = (int)(v>>>32);
-        nWords = (data[1]==0) ? 1 : 2;
-    }
-
-    public FDBigInt( FDBigInt other ){
-        data = new int[nWords = other.nWords];
-        System.arraycopy( other.data, 0, data, 0, nWords );
-    }
-
-    private FDBigInt( int [] d, int n ){
-        data = d;
-        nWords = n;
-    }
-
-    public FDBigInt( long seed, char digit[], int nd0, int nd ){
-        int n= (nd+8)/9;        // estimate size needed.
-        if ( n < 2 ) n = 2;
-        data = new int[n];      // allocate enough space
-        data[0] = (int)seed;    // starting value
-        data[1] = (int)(seed>>>32);
-        nWords = (data[1]==0) ? 1 : 2;
-        int i = nd0;
-        int limit = nd-5;       // slurp digits 5 at a time.
-        int v;
-        while ( i < limit ){
-            int ilim = i+5;
-            v = (int)digit[i++]-(int)'0';
-            while( i <ilim ){
-                v = 10*v + (int)digit[i++]-(int)'0';
-            }
-            multaddMe( 100000, v); // ... where 100000 is 10^5.
-        }
-        int factor = 1;
-        v = 0;
-        while ( i < nd ){
-            v = 10*v + (int)digit[i++]-(int)'0';
-            factor *= 10;
-        }
-        if ( factor != 1 ){
-            multaddMe( factor, v );
-        }
-    }
-
-    /*
-     * Left shift by c bits.
-     * Shifts this in place.
-     */
-    public void
-    lshiftMe( int c )throws IllegalArgumentException {
-        if ( c <= 0 ){
-            if ( c == 0 )
-                return; // silly.
-            else
-                throw new IllegalArgumentException("negative shift count");
-        }
-        int wordcount = c>>5;
-        int bitcount  = c & 0x1f;
-        int anticount = 32-bitcount;
-        int t[] = data;
-        int s[] = data;
-        if ( nWords+wordcount+1 > t.length ){
-            // reallocate.
-            t = new int[ nWords+wordcount+1 ];
-        }
-        int target = nWords+wordcount;
-        int src    = nWords-1;
-        if ( bitcount == 0 ){
-            // special hack, since an anticount of 32 won't go!
-            System.arraycopy( s, 0, t, wordcount, nWords );
-            target = wordcount-1;
-        } else {
-            t[target--] = s[src]>>>anticount;
-            while ( src >= 1 ){
-                t[target--] = (s[src]<<bitcount) | (s[--src]>>>anticount);
-            }
-            t[target--] = s[src]<<bitcount;
-        }
-        while( target >= 0 ){
-            t[target--] = 0;
-        }
-        data = t;
-        nWords += wordcount + 1;
-        // may have constructed high-order word of 0.
-        // if so, trim it
-        while ( nWords > 1 && data[nWords-1] == 0 )
-            nWords--;
-    }
-
-    /*
-     * normalize this number by shifting until
-     * the MSB of the number is at 0x08000000.
-     * This is in preparation for quoRemIteration, below.
-     * The idea is that, to make division easier, we want the
-     * divisor to be "normalized" -- usually this means shifting
-     * the MSB into the high words sign bit. But because we know that
-     * the quotient will be 0 < q < 10, we would like to arrange that
-     * the dividend not span up into another word of precision.
-     * (This needs to be explained more clearly!)
-     */
-    public int
-    normalizeMe() throws IllegalArgumentException {
-        int src;
-        int wordcount = 0;
-        int bitcount  = 0;
-        int v = 0;
-        for ( src= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){
-            wordcount += 1;
-        }
-        if ( src < 0 ){
-            // oops. Value is zero. Cannot normalize it!
-            throw new IllegalArgumentException("zero value");
-        }
-        /*
-         * In most cases, we assume that wordcount is zero. This only
-         * makes sense, as we try not to maintain any high-order
-         * words full of zeros. In fact, if there are zeros, we will
-         * simply SHORTEN our number at this point. Watch closely...
-         */
-        nWords -= wordcount;
-        /*
-         * Compute how far left we have to shift v s.t. its highest-
-         * order bit is in the right place. Then call lshiftMe to
-         * do the work.
-         */
-        if ( (v & 0xf0000000) != 0 ){
-            // will have to shift up into the next word.
-            // too bad.
-            for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- )
-                v >>>= 1;
-        } else {
-            while ( v <= 0x000fffff ){
-                // hack: byte-at-a-time shifting
-                v <<= 8;
-                bitcount += 8;
-            }
-            while ( v <= 0x07ffffff ){
-                v <<= 1;
-                bitcount += 1;
-            }
-        }
-        if ( bitcount != 0 )
-            lshiftMe( bitcount );
-        return bitcount;
-    }
-
-    /*
-     * Multiply a FDBigInt by an int.
-     * Result is a new FDBigInt.
-     */
-    public FDBigInt
-    mult( int iv ) {
-        long v = iv;
-        int r[];
-        long p;
-
-        // guess adequate size of r.
-        r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ];
-        p = 0L;
-        for( int i=0; i < nWords; i++ ) {
-            p += v * ((long)data[i]&0xffffffffL);
-            r[i] = (int)p;
-            p >>>= 32;
-        }
-        if ( p == 0L){
-            return new FDBigInt( r, nWords );
-        } else {
-            r[nWords] = (int)p;
-            return new FDBigInt( r, nWords+1 );
-        }
-    }
-
-    /*
-     * Multiply a FDBigInt by an int and add another int.
-     * Result is computed in place.
-     * Hope it fits!
-     */
-    public void
-    multaddMe( int iv, int addend ) {
-        long v = iv;
-        long p;
-
-        // unroll 0th iteration, doing addition.
-        p = v * ((long)data[0]&0xffffffffL) + ((long)addend&0xffffffffL);
-        data[0] = (int)p;
-        p >>>= 32;
-        for( int i=1; i < nWords; i++ ) {
-            p += v * ((long)data[i]&0xffffffffL);
-            data[i] = (int)p;
-            p >>>= 32;
-        }
-        if ( p != 0L){
-            data[nWords] = (int)p; // will fail noisily if illegal!
-            nWords++;
-        }
-    }
-
-    /*
-     * Multiply a FDBigInt by another FDBigInt.
-     * Result is a new FDBigInt.
-     */
-    public FDBigInt
-    mult( FDBigInt other ){
-        // crudely guess adequate size for r
-        int r[] = new int[ nWords + other.nWords ];
-        int i;
-        // I think I am promised zeros...
-
-        for( i = 0; i < this.nWords; i++ ){
-            long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
-            long p = 0L;
-            int j;
-            for( j = 0; j < other.nWords; j++ ){
-                p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
-                r[i+j] = (int)p;
-                p >>>= 32;
-            }
-            r[i+j] = (int)p;
-        }
-        // compute how much of r we actually needed for all that.
-        for ( i = r.length-1; i> 0; i--)
-            if ( r[i] != 0 )
-                break;
-        return new FDBigInt( r, i+1 );
-    }
-
-    /*
-     * Add one FDBigInt to another. Return a FDBigInt
-     */
-    public FDBigInt
-    add( FDBigInt other ){
-        int i;
-        int a[], b[];
-        int n, m;
-        long c = 0L;
-        // arrange such that a.nWords >= b.nWords;
-        // n = a.nWords, m = b.nWords
-        if ( this.nWords >= other.nWords ){
-            a = this.data;
-            n = this.nWords;
-            b = other.data;
-            m = other.nWords;
-        } else {
-            a = other.data;
-            n = other.nWords;
-            b = this.data;
-            m = this.nWords;
-        }
-        int r[] = new int[ n ];
-        for ( i = 0; i < n; i++ ){
-            c += (long)a[i] & 0xffffffffL;
-            if ( i < m ){
-                c += (long)b[i] & 0xffffffffL;
-            }
-            r[i] = (int) c;
-            c >>= 32; // signed shift.
-        }
-        if ( c != 0L ){
-            // oops -- carry out -- need longer result.
-            int s[] = new int[ r.length+1 ];
-            System.arraycopy( r, 0, s, 0, r.length );
-            s[i++] = (int)c;
-            return new FDBigInt( s, i );
-        }
-        return new FDBigInt( r, i );
-    }
-
-    /*
-     * Subtract one FDBigInt from another. Return a FDBigInt
-     * Assert that the result is positive.
-     */
-    public FDBigInt
-    sub( FDBigInt other ){
-        int r[] = new int[ this.nWords ];
-        int i;
-        int n = this.nWords;
-        int m = other.nWords;
-        int nzeros = 0;
-        long c = 0L;
-        for ( i = 0; i < n; i++ ){
-            c += (long)this.data[i] & 0xffffffffL;
-            if ( i < m ){
-                c -= (long)other.data[i] & 0xffffffffL;
-            }
-            if ( ( r[i] = (int) c ) == 0 )
-                nzeros++;
-            else
-                nzeros = 0;
-            c >>= 32; // signed shift
-        }
-        assert c == 0L : c; // borrow out of subtract
-        assert dataInRangeIsZero(i, m, other); // negative result of subtract
-        return new FDBigInt( r, n-nzeros );
-    }
-
-    private static boolean dataInRangeIsZero(int i, int m, FDBigInt other) {
-        while ( i < m )
-            if (other.data[i++] != 0)
-                return false;
-        return true;
-    }
-
-    /*
-     * Compare FDBigInt with another FDBigInt. Return an integer
-     * >0: this > other
-     *  0: this == other
-     * <0: this < other
-     */
-    public int
-    cmp( FDBigInt other ){
-        int i;
-        if ( this.nWords > other.nWords ){
-            // if any of my high-order words is non-zero,
-            // then the answer is evident
-            int j = other.nWords-1;
-            for ( i = this.nWords-1; i > j ; i-- )
-                if ( this.data[i] != 0 ) return 1;
-        }else if ( this.nWords < other.nWords ){
-            // if any of other's high-order words is non-zero,
-            // then the answer is evident
-            int j = this.nWords-1;
-            for ( i = other.nWords-1; i > j ; i-- )
-                if ( other.data[i] != 0 ) return -1;
-        } else{
-            i = this.nWords-1;
-        }
-        for ( ; i > 0 ; i-- )
-            if ( this.data[i] != other.data[i] )
-                break;
-        // careful! want unsigned compare!
-        // use brute force here.
-        int a = this.data[i];
-        int b = other.data[i];
-        if ( a < 0 ){
-            // a is really big, unsigned
-            if ( b < 0 ){
-                return a-b; // both big, negative
-            } else {
-                return 1; // b not big, answer is obvious;
-            }
-        } else {
-            // a is not really big
-            if ( b < 0 ) {
-                // but b is really big
-                return -1;
-            } else {
-                return a - b;
-            }
-        }
-    }
-
-    /*
-     * Compute
-     * q = (int)( this / S )
-     * this = 10 * ( this mod S )
-     * Return q.
-     * This is the iteration step of digit development for output.
-     * We assume that S has been normalized, as above, and that
-     * "this" has been lshift'ed accordingly.
-     * Also assume, of course, that the result, q, can be expressed
-     * as an integer, 0 <= q < 10.
-     */
-    public int
-    quoRemIteration( FDBigInt S )throws IllegalArgumentException {
-        // ensure that this and S have the same number of
-        // digits. If S is properly normalized and q < 10 then
-        // this must be so.
-        if ( nWords != S.nWords ){
-            throw new IllegalArgumentException("disparate values");
-        }
-        // estimate q the obvious way. We will usually be
-        // right. If not, then we're only off by a little and
-        // will re-add.
-        int n = nWords-1;
-        long q = ((long)data[n]&0xffffffffL) / (long)S.data[n];
-        long diff = 0L;
-        for ( int i = 0; i <= n ; i++ ){
-            diff += ((long)data[i]&0xffffffffL) -  q*((long)S.data[i]&0xffffffffL);
-            data[i] = (int)diff;
-            diff >>= 32; // N.B. SIGNED shift.
-        }
-        if ( diff != 0L ) {
-            // damn, damn, damn. q is too big.
-            // add S back in until this turns +. This should
-            // not be very many times!
-            long sum = 0L;
-            while ( sum ==  0L ){
-                sum = 0L;
-                for ( int i = 0; i <= n; i++ ){
-                    sum += ((long)data[i]&0xffffffffL) +  ((long)S.data[i]&0xffffffffL);
-                    data[i] = (int) sum;
-                    sum >>= 32; // Signed or unsigned, answer is 0 or 1
-                }
-                /*
-                 * Originally the following line read
-                 * "if ( sum !=0 && sum != -1 )"
-                 * but that would be wrong, because of the
-                 * treatment of the two values as entirely unsigned,
-                 * it would be impossible for a carry-out to be interpreted
-                 * as -1 -- it would have to be a single-bit carry-out, or
-                 * +1.
-                 */
-                assert sum == 0 || sum == 1 : sum; // carry out of division correction
-                q -= 1;
-            }
-        }
-        // finally, we can multiply this by 10.
-        // it cannot overflow, right, as the high-order word has
-        // at least 4 high-order zeros!
-        long p = 0L;
-        for ( int i = 0; i <= n; i++ ){
-            p += 10*((long)data[i]&0xffffffffL);
-            data[i] = (int)p;
-            p >>= 32; // SIGNED shift.
-        }
-        assert p == 0L : p; // Carry out of *10
-        return (int)q;
-    }
-
-    public long
-    longValue(){
-        // if this can be represented as a long, return the value
-        assert this.nWords > 0 : this.nWords; // longValue confused
-
-        if (this.nWords == 1)
-            return ((long)data[0]&0xffffffffL);
-
-        assert dataInRangeIsZero(2, this.nWords, this); // value too big
-        assert data[1] >= 0;  // value too big
-        return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL);
-    }
-
-    public String
-    toString() {
-        StringBuffer r = new StringBuffer(30);
-        r.append('[');
-        int i = Math.min( nWords-1, data.length-1) ;
-        if ( nWords > data.length ){
-            r.append( "("+data.length+"<"+nWords+"!)" );
-        }
-        for( ; i> 0 ; i-- ){
-            r.append( Integer.toHexString( data[i] ) );
-            r.append(' ');
-        }
-        r.append( Integer.toHexString( data[0] ) );
-        r.append(']');
-        return new String( r );
-    }
-}
diff --git a/ojluni/src/main/java/sun/misc/FpUtils.java b/ojluni/src/main/java/sun/misc/FpUtils.java
index 1050d32..a874c80 100644
--- a/ojluni/src/main/java/sun/misc/FpUtils.java
+++ b/ojluni/src/main/java/sun/misc/FpUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -125,10 +125,6 @@
      */
     private FpUtils() {}
 
-    // Constants used in scalb
-    static double twoToTheDoubleScaleUp = powerOfTwoD(512);
-    static double twoToTheDoubleScaleDown = powerOfTwoD(-512);
-
     // Helper Methods
 
     // The following helper methods are used in the implementation of
@@ -137,49 +133,22 @@
 
     /**
      * Returns unbiased exponent of a {@code double}.
+     * @deprecated Use Math.getExponent.
      */
+    @Deprecated
     public static int getExponent(double d){
-        /*
-         * Bitwise convert d to long, mask out exponent bits, shift
-         * to the right and then subtract out double's bias adjust to
-         * get true exponent value.
-         */
-        return (int)(((Double.doubleToRawLongBits(d) & DoubleConsts.EXP_BIT_MASK) >>
-                      (DoubleConsts.SIGNIFICAND_WIDTH - 1)) - DoubleConsts.EXP_BIAS);
+        return Math.getExponent(d);
     }
 
     /**
      * Returns unbiased exponent of a {@code float}.
+     * @deprecated Use Math.getExponent.
      */
+    @Deprecated
     public static int getExponent(float f){
-        /*
-         * Bitwise convert f to integer, mask out exponent bits, shift
-         * to the right and then subtract out float's bias adjust to
-         * get true exponent value
-         */
-        return ((Float.floatToRawIntBits(f) & FloatConsts.EXP_BIT_MASK) >>
-                (FloatConsts.SIGNIFICAND_WIDTH - 1)) - FloatConsts.EXP_BIAS;
+        return Math.getExponent(f);
     }
 
-    /**
-     * Returns a floating-point power of two in the normal range.
-     */
-    static double powerOfTwoD(int n) {
-        assert(n >= DoubleConsts.MIN_EXPONENT && n <= DoubleConsts.MAX_EXPONENT);
-        return Double.longBitsToDouble((((long)n + (long)DoubleConsts.EXP_BIAS) <<
-                                        (DoubleConsts.SIGNIFICAND_WIDTH-1))
-                                       & DoubleConsts.EXP_BIT_MASK);
-    }
-
-    /**
-     * Returns a floating-point power of two in the normal range.
-     */
-    static float powerOfTwoF(int n) {
-        assert(n >= FloatConsts.MIN_EXPONENT && n <= FloatConsts.MAX_EXPONENT);
-        return Float.intBitsToFloat(((n + FloatConsts.EXP_BIAS) <<
-                                     (FloatConsts.SIGNIFICAND_WIDTH-1))
-                                    & FloatConsts.EXP_BIT_MASK);
-    }
 
     /**
      * Returns the first floating-point argument with the sign of the
@@ -195,13 +164,11 @@
      * @return a value with the magnitude of {@code magnitude}
      * and the sign of {@code sign}.
      * @author Joseph D. Darcy
+     * @deprecated Use Math.copySign.
      */
+    @Deprecated
     public static double rawCopySign(double magnitude, double sign) {
-        return Double.longBitsToDouble((Double.doubleToRawLongBits(sign) &
-                                        (DoubleConsts.SIGN_BIT_MASK)) |
-                                       (Double.doubleToRawLongBits(magnitude) &
-                                        (DoubleConsts.EXP_BIT_MASK |
-                                         DoubleConsts.SIGNIF_BIT_MASK)));
+        return Math.copySign(magnitude, sign);
     }
 
     /**
@@ -218,13 +185,11 @@
      * @return a value with the magnitude of {@code magnitude}
      * and the sign of {@code sign}.
      * @author Joseph D. Darcy
+     * @deprecated Use Math.copySign.
      */
+    @Deprecated
     public static float rawCopySign(float magnitude, float sign) {
-        return Float.intBitsToFloat((Float.floatToRawIntBits(sign) &
-                                     (FloatConsts.SIGN_BIT_MASK)) |
-                                    (Float.floatToRawIntBits(magnitude) &
-                                     (FloatConsts.EXP_BIT_MASK |
-                                      FloatConsts.SIGNIF_BIT_MASK)));
+        return Math.copySign(magnitude, sign);
     }
 
     /* ***************************************************************** */
@@ -237,9 +202,11 @@
      * @param d the {@code double} value to be tested
      * @return {@code true} if the argument is a finite
      * floating-point value, {@code false} otherwise.
+     * @deprecated Use Double.isFinite.
      */
+    @Deprecated
     public static boolean isFinite(double d) {
-        return Math.abs(d) <= DoubleConsts.MAX_VALUE;
+        return Double.isFinite(d);
     }
 
     /**
@@ -250,9 +217,11 @@
      * @param f the {@code float} value to be tested
      * @return {@code true} if the argument is a finite
      * floating-point value, {@code false} otherwise.
+     * @deprecated Use Float.isFinite.
      */
+     @Deprecated
      public static boolean isFinite(float f) {
-        return Math.abs(f) <= FloatConsts.MAX_VALUE;
+         return Float.isFinite(f);
     }
 
     /**
@@ -558,82 +527,11 @@
      * @param scale_factor power of 2 used to scale {@code d}
      * @return {@code d * }2<sup>{@code scale_factor}</sup>
      * @author Joseph D. Darcy
+     * @deprecated Use Math.scalb.
      */
+    @Deprecated
     public static double scalb(double d, int scale_factor) {
-        /*
-         * This method does not need to be declared strictfp to
-         * compute the same correct result on all platforms.  When
-         * scaling up, it does not matter what order the
-         * multiply-store operations are done; the result will be
-         * finite or overflow regardless of the operation ordering.
-         * However, to get the correct result when scaling down, a
-         * particular ordering must be used.
-         *
-         * When scaling down, the multiply-store operations are
-         * sequenced so that it is not possible for two consecutive
-         * multiply-stores to return subnormal results.  If one
-         * multiply-store result is subnormal, the next multiply will
-         * round it away to zero.  This is done by first multiplying
-         * by 2 ^ (scale_factor % n) and then multiplying several
-         * times by by 2^n as needed where n is the exponent of number
-         * that is a covenient power of two.  In this way, at most one
-         * real rounding error occurs.  If the double value set is
-         * being used exclusively, the rounding will occur on a
-         * multiply.  If the double-extended-exponent value set is
-         * being used, the products will (perhaps) be exact but the
-         * stores to d are guaranteed to round to the double value
-         * set.
-         *
-         * It is _not_ a valid implementation to first multiply d by
-         * 2^MIN_EXPONENT and then by 2 ^ (scale_factor %
-         * MIN_EXPONENT) since even in a strictfp program double
-         * rounding on underflow could occur; e.g. if the scale_factor
-         * argument was (MIN_EXPONENT - n) and the exponent of d was a
-         * little less than -(MIN_EXPONENT - n), meaning the final
-         * result would be subnormal.
-         *
-         * Since exact reproducibility of this method can be achieved
-         * without any undue performance burden, there is no
-         * compelling reason to allow double rounding on underflow in
-         * scalb.
-         */
-
-        // magnitude of a power of two so large that scaling a finite
-        // nonzero value by it would be guaranteed to over or
-        // underflow; due to rounding, scaling down takes takes an
-        // additional power of two which is reflected here
-        final int MAX_SCALE = DoubleConsts.MAX_EXPONENT + -DoubleConsts.MIN_EXPONENT +
-                              DoubleConsts.SIGNIFICAND_WIDTH + 1;
-        int exp_adjust = 0;
-        int scale_increment = 0;
-        double exp_delta = Double.NaN;
-
-        // Make sure scaling factor is in a reasonable range
-
-        if(scale_factor < 0) {
-            scale_factor = Math.max(scale_factor, -MAX_SCALE);
-            scale_increment = -512;
-            exp_delta = twoToTheDoubleScaleDown;
-        }
-        else {
-            scale_factor = Math.min(scale_factor, MAX_SCALE);
-            scale_increment = 512;
-            exp_delta = twoToTheDoubleScaleUp;
-        }
-
-        // Calculate (scale_factor % +/-512), 512 = 2^9, using
-        // technique from "Hacker's Delight" section 10-2.
-        int t = (scale_factor >> 9-1) >>> 32 - 9;
-        exp_adjust = ((scale_factor + t) & (512 -1)) - t;
-
-        d *= powerOfTwoD(exp_adjust);
-        scale_factor -= exp_adjust;
-
-        while(scale_factor != 0) {
-            d *= exp_delta;
-            scale_factor -= scale_increment;
-        }
-        return d;
+        return Math.scalb(d, scale_factor);
     }
 
     /**
@@ -667,28 +565,11 @@
      * @param scale_factor power of 2 used to scale {@code f}
      * @return {@code f * }2<sup>{@code scale_factor}</sup>
      * @author Joseph D. Darcy
+     * @deprecated Use Math.scalb.
      */
-     public static float scalb(float f, int scale_factor) {
-        // magnitude of a power of two so large that scaling a finite
-        // nonzero value by it would be guaranteed to over or
-        // underflow; due to rounding, scaling down takes takes an
-        // additional power of two which is reflected here
-        final int MAX_SCALE = FloatConsts.MAX_EXPONENT + -FloatConsts.MIN_EXPONENT +
-                              FloatConsts.SIGNIFICAND_WIDTH + 1;
-
-        // Make sure scaling factor is in a reasonable range
-        scale_factor = Math.max(Math.min(scale_factor, MAX_SCALE), -MAX_SCALE);
-
-        /*
-         * Since + MAX_SCALE for float fits well within the double
-         * exponent range and + float -> double conversion is exact
-         * the multiplication below will be exact. Therefore, the
-         * rounding that occurs when the double product is cast to
-         * float will be the correctly rounded float result.  Since
-         * all operations other than the final multiply will be exact,
-         * it is not necessary to declare this method strictfp.
-         */
-        return (float)((double)f*powerOfTwoD(scale_factor));
+    @Deprecated
+    public static float scalb(float f, int scale_factor) {
+        return Math.scalb(f, scale_factor);
     }
 
     /**
@@ -730,65 +611,11 @@
      * @return The floating-point number adjacent to {@code start} in the
      * direction of {@code direction}.
      * @author Joseph D. Darcy
+     * @deprecated Use Math.nextAfter
      */
+    @Deprecated
     public static double nextAfter(double start, double direction) {
-        /*
-         * The cases:
-         *
-         * nextAfter(+infinity, 0)  == MAX_VALUE
-         * nextAfter(+infinity, +infinity)  == +infinity
-         * nextAfter(-infinity, 0)  == -MAX_VALUE
-         * nextAfter(-infinity, -infinity)  == -infinity
-         *
-         * are naturally handled without any additional testing
-         */
-
-        // First check for NaN values
-        if (isNaN(start) || isNaN(direction)) {
-            // return a NaN derived from the input NaN(s)
-            return start + direction;
-        } else if (start == direction) {
-            return direction;
-        } else {        // start > direction or start < direction
-            // Add +0.0 to get rid of a -0.0 (+0.0 + -0.0 => +0.0)
-            // then bitwise convert start to integer.
-            long transducer = Double.doubleToRawLongBits(start + 0.0d);
-
-            /*
-             * IEEE 754 floating-point numbers are lexicographically
-             * ordered if treated as signed- magnitude integers .
-             * Since Java's integers are two's complement,
-             * incrementing" the two's complement representation of a
-             * logically negative floating-point value *decrements*
-             * the signed-magnitude representation. Therefore, when
-             * the integer representation of a floating-point values
-             * is less than zero, the adjustment to the representation
-             * is in the opposite direction than would be expected at
-             * first .
-             */
-            if (direction > start) { // Calculate next greater value
-                transducer = transducer + (transducer >= 0L ? 1L:-1L);
-            } else  { // Calculate next lesser value
-                assert direction < start;
-                if (transducer > 0L)
-                    --transducer;
-                else
-                    if (transducer < 0L )
-                        ++transducer;
-                    /*
-                     * transducer==0, the result is -MIN_VALUE
-                     *
-                     * The transition from zero (implicitly
-                     * positive) to the smallest negative
-                     * signed magnitude value must be done
-                     * explicitly.
-                     */
-                    else
-                        transducer = DoubleConsts.SIGN_BIT_MASK | 1L;
-            }
-
-            return Double.longBitsToDouble(transducer);
-        }
+        return Math.nextAfter(start, direction);
     }
 
     /**
@@ -830,65 +657,11 @@
      * @return The floating-point number adjacent to {@code start} in the
      * direction of {@code direction}.
      * @author Joseph D. Darcy
+     * @deprecated Use Math.nextAfter.
      */
-     public static float nextAfter(float start, double direction) {
-        /*
-         * The cases:
-         *
-         * nextAfter(+infinity, 0)  == MAX_VALUE
-         * nextAfter(+infinity, +infinity)  == +infinity
-         * nextAfter(-infinity, 0)  == -MAX_VALUE
-         * nextAfter(-infinity, -infinity)  == -infinity
-         *
-         * are naturally handled without any additional testing
-         */
-
-        // First check for NaN values
-        if (isNaN(start) || isNaN(direction)) {
-            // return a NaN derived from the input NaN(s)
-            return start + (float)direction;
-        } else if (start == direction) {
-            return (float)direction;
-        } else {        // start > direction or start < direction
-            // Add +0.0 to get rid of a -0.0 (+0.0 + -0.0 => +0.0)
-            // then bitwise convert start to integer.
-            int transducer = Float.floatToRawIntBits(start + 0.0f);
-
-            /*
-             * IEEE 754 floating-point numbers are lexicographically
-             * ordered if treated as signed- magnitude integers .
-             * Since Java's integers are two's complement,
-             * incrementing" the two's complement representation of a
-             * logically negative floating-point value *decrements*
-             * the signed-magnitude representation. Therefore, when
-             * the integer representation of a floating-point values
-             * is less than zero, the adjustment to the representation
-             * is in the opposite direction than would be expected at
-             * first.
-             */
-            if (direction > start) {// Calculate next greater value
-                transducer = transducer + (transducer >= 0 ? 1:-1);
-            } else  { // Calculate next lesser value
-                assert direction < start;
-                if (transducer > 0)
-                    --transducer;
-                else
-                    if (transducer < 0 )
-                        ++transducer;
-                    /*
-                     * transducer==0, the result is -MIN_VALUE
-                     *
-                     * The transition from zero (implicitly
-                     * positive) to the smallest negative
-                     * signed magnitude value must be done
-                     * explicitly.
-                     */
-                    else
-                        transducer = FloatConsts.SIGN_BIT_MASK | 1;
-            }
-
-            return Float.intBitsToFloat(transducer);
-        }
+    @Deprecated
+    public static float nextAfter(float start, double direction) {
+        return Math.nextAfter(start, direction);
     }
 
     /**
@@ -915,15 +688,11 @@
      * @return The adjacent floating-point value closer to positive
      * infinity.
      * @author Joseph D. Darcy
+     * @deprecated use Math.nextUp.
      */
+    @Deprecated
     public static double nextUp(double d) {
-        if( isNaN(d) || d == Double.POSITIVE_INFINITY)
-            return d;
-        else {
-            d += 0.0d;
-            return Double.longBitsToDouble(Double.doubleToRawLongBits(d) +
-                                           ((d >= 0.0d)?+1L:-1L));
-        }
+        return Math.nextUp(d);
     }
 
     /**
@@ -950,15 +719,11 @@
      * @return The adjacent floating-point value closer to positive
      * infinity.
      * @author Joseph D. Darcy
+     * @deprecated Use Math.nextUp.
      */
-     public static float nextUp(float f) {
-        if( isNaN(f) || f == FloatConsts.POSITIVE_INFINITY)
-            return f;
-        else {
-            f += 0.0f;
-            return Float.intBitsToFloat(Float.floatToRawIntBits(f) +
-                                        ((f >= 0.0f)?+1:-1));
-        }
+    @Deprecated
+    public static float nextUp(float f) {
+        return Math.nextUp(f);
     }
 
     /**
@@ -985,17 +750,11 @@
      * @return The adjacent floating-point value closer to negative
      * infinity.
      * @author Joseph D. Darcy
+     * @deprecated Use Math.nextDown.
      */
+    @Deprecated
     public static double nextDown(double d) {
-        if( isNaN(d) || d == Double.NEGATIVE_INFINITY)
-            return d;
-        else {
-            if (d == 0.0)
-                return -Double.MIN_VALUE;
-            else
-                return Double.longBitsToDouble(Double.doubleToRawLongBits(d) +
-                                               ((d > 0.0d)?-1L:+1L));
-        }
+        return Math.nextDown(d);
     }
 
     /**
@@ -1022,17 +781,11 @@
      * @return The adjacent floating-point value closer to negative
      * infinity.
      * @author Joseph D. Darcy
+     * @deprecated Use Math.nextDown.
      */
+    @Deprecated
     public static double nextDown(float f) {
-        if( isNaN(f) || f == Float.NEGATIVE_INFINITY)
-            return f;
-        else {
-            if (f == 0.0f)
-                return -Float.MIN_VALUE;
-            else
-                return Float.intBitsToFloat(Float.floatToRawIntBits(f) +
-                                            ((f > 0.0f)?-1:+1));
-        }
+        return Math.nextDown(f);
     }
 
     /**
@@ -1047,9 +800,11 @@
      * and the sign of {@code sign}.
      * @author Joseph D. Darcy
      * @since 1.5
+     * @deprecated Use StrictMath.copySign.
      */
+    @Deprecated
     public static double copySign(double magnitude, double sign) {
-        return rawCopySign(magnitude, (isNaN(sign)?1.0d:sign));
+        return StrictMath.copySign(magnitude, sign);
     }
 
     /**
@@ -1063,9 +818,11 @@
      * @return a value with the magnitude of {@code magnitude}
      * and the sign of {@code sign}.
      * @author Joseph D. Darcy
+     * @deprecated Use StrictMath.copySign.
      */
-     public static float copySign(float magnitude, float sign) {
-        return rawCopySign(magnitude, (isNaN(sign)?1.0f:sign));
+    @Deprecated
+    public static float copySign(float magnitude, float sign) {
+        return StrictMath.copySign(magnitude, sign);
     }
 
     /**
@@ -1090,33 +847,11 @@
      * @return the size of an ulp of the argument
      * @author Joseph D. Darcy
      * @since 1.5
+     * @deprecated Use Math.ulp.
      */
+    @Deprecated
     public static double ulp(double d) {
-        int exp = getExponent(d);
-
-        switch(exp) {
-        case DoubleConsts.MAX_EXPONENT+1:       // NaN or infinity
-            return Math.abs(d);
-
-        case DoubleConsts.MIN_EXPONENT-1:       // zero or subnormal
-            return Double.MIN_VALUE;
-
-        default:
-            assert exp <= DoubleConsts.MAX_EXPONENT && exp >= DoubleConsts.MIN_EXPONENT;
-
-            // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
-            exp = exp - (DoubleConsts.SIGNIFICAND_WIDTH-1);
-            if (exp >= DoubleConsts.MIN_EXPONENT) {
-                return powerOfTwoD(exp);
-            }
-            else {
-                // return a subnormal result; left shift integer
-                // representation of Double.MIN_VALUE appropriate
-                // number of positions
-                return Double.longBitsToDouble(1L <<
-                (exp - (DoubleConsts.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH-1)) ));
-            }
-        }
+        return Math.ulp(d);
     }
 
     /**
@@ -1141,33 +876,11 @@
      * @return the size of an ulp of the argument
      * @author Joseph D. Darcy
      * @since 1.5
+     * @deprecated Use Math.ulp.
      */
+     @Deprecated
      public static float ulp(float f) {
-        int exp = getExponent(f);
-
-        switch(exp) {
-        case FloatConsts.MAX_EXPONENT+1:        // NaN or infinity
-            return Math.abs(f);
-
-        case FloatConsts.MIN_EXPONENT-1:        // zero or subnormal
-            return FloatConsts.MIN_VALUE;
-
-        default:
-            assert exp <= FloatConsts.MAX_EXPONENT && exp >= FloatConsts.MIN_EXPONENT;
-
-            // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
-            exp = exp - (FloatConsts.SIGNIFICAND_WIDTH-1);
-            if (exp >= FloatConsts.MIN_EXPONENT) {
-                return powerOfTwoF(exp);
-            }
-            else {
-                // return a subnormal result; left shift integer
-                // representation of FloatConsts.MIN_VALUE appropriate
-                // number of positions
-                return Float.intBitsToFloat(1 <<
-                (exp - (FloatConsts.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH-1)) ));
-            }
-        }
+        return Math.ulp(f);
      }
 
     /**
@@ -1186,9 +899,11 @@
      * @return the signum function of the argument
      * @author Joseph D. Darcy
      * @since 1.5
+     * @deprecated Use Math.signum.
      */
+    @Deprecated
     public static double signum(double d) {
-        return (d == 0.0 || isNaN(d))?d:copySign(1.0, d);
+        return Math.signum(d);
     }
 
     /**
@@ -1207,9 +922,10 @@
      * @return the signum function of the argument
      * @author Joseph D. Darcy
      * @since 1.5
+     * @deprecated Use Math.signum.
      */
+    @Deprecated
     public static float signum(float f) {
-        return (f == 0.0f || isNaN(f))?f:copySign(1.0f, f);
+        return Math.signum(f);
     }
-
 }
diff --git a/ojluni/src/main/java/sun/misc/Hashing.java b/ojluni/src/main/java/sun/misc/Hashing.java
deleted file mode 100644
index 2b3b144..0000000
--- a/ojluni/src/main/java/sun/misc/Hashing.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.misc;
-
-import java.util.concurrent.ThreadLocalRandom;
-
-/**
- * Hashing utilities.
- *
- * Little endian implementations of Murmur3 hashing.
- */
-public class Hashing {
-
-    /**
-     * Static utility methods only.
-     */
-    private Hashing() {
-        throw new Error("No instances");
-    }
-
-    // Spread bits to regularize both segment and index locations,
-    // using variant of single-word Wang/Jenkins hash.
-    //
-    // Based on commit 1424a2a1a9fc53dc8b859a77c02c924.
-    public static int singleWordWangJenkinsHash(Object k) {
-        int h = k.hashCode();
-
-        h += (h <<  15) ^ 0xffffcd7d;
-        h ^= (h >>> 10);
-        h += (h <<   3);
-        h ^= (h >>>  6);
-        h += (h <<   2) + (h << 14);
-        return h ^ (h >>> 16);
-    }
-}
diff --git a/ojluni/src/main/java/sun/misc/InvalidJarIndexException.java b/ojluni/src/main/java/sun/misc/InvalidJarIndexException.java
index 83e8199..44ca4ff 100644
--- a/ojluni/src/main/java/sun/misc/InvalidJarIndexException.java
+++ b/ojluni/src/main/java/sun/misc/InvalidJarIndexException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,8 @@
 public
 class InvalidJarIndexException extends RuntimeException {
 
+    static final long serialVersionUID = -6159797516569680148L;
+
     /**
      * Constructs an <code>InvalidJarIndexException</code> with no
      * detail message.
diff --git a/ojluni/src/main/java/sun/misc/JarIndex.java b/ojluni/src/main/java/sun/misc/JarIndex.java
index f9781d6..6e08cf2 100644
--- a/ojluni/src/main/java/sun/misc/JarIndex.java
+++ b/ojluni/src/main/java/sun/misc/JarIndex.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,11 @@
 package sun.misc;
 
 import java.io.*;
+import java.security.AccessController;
 import java.util.*;
 import java.util.jar.*;
 import java.util.zip.*;
+import sun.security.action.GetPropertyAction;
 
 /**
  * This class is used to maintain mappings from packages, classes
@@ -48,13 +50,13 @@
      * The hash map that maintains mappings from
      * package/classe/resource to jar file list(s)
      */
-    private HashMap indexMap;
+    private HashMap<String,LinkedList<String>> indexMap;
 
     /**
      * The hash map that maintains mappings from
      * jar file to package/class/resource lists
      */
-    private HashMap jarMap;
+    private HashMap<String,LinkedList<String>> jarMap;
 
     /*
      * An ordered list of jar file names.
@@ -72,14 +74,15 @@
      * be added to the index. Otherwise, just the directory names are added.
      */
     private static final boolean metaInfFilenames =
-        "true".equals(System.getProperty("sun.misc.JarIndex.metaInfFilenames"));
+        "true".equals(AccessController.doPrivileged(
+             new GetPropertyAction("sun.misc.JarIndex.metaInfFilenames")));
 
     /**
      * Constructs a new, empty jar index.
      */
     public JarIndex() {
-        indexMap = new HashMap();
-        jarMap = new HashMap();
+        indexMap = new HashMap<>();
+        jarMap = new HashMap<>();
     }
 
     /**
@@ -150,10 +153,11 @@
      * Add the key, value pair to the hashmap, the value will
      * be put in a linked list which is created if necessary.
      */
-    private void addToList(String key, String value, HashMap t) {
-        LinkedList list = (LinkedList)t.get(key);
+    private void addToList(String key, String value,
+                           HashMap<String,LinkedList<String>> t) {
+        LinkedList<String> list = t.get(key);
         if (list == null) {
-            list = new LinkedList();
+            list = new LinkedList<>();
             list.add(value);
             t.put(key, list);
         } else if (!list.contains(value)) {
@@ -166,13 +170,13 @@
      *
      * @param fileName the key of the mapping
      */
-    public LinkedList get(String fileName) {
-        LinkedList jarFiles = null;
-        if ((jarFiles = (LinkedList)indexMap.get(fileName)) == null) {
+    public LinkedList<String> get(String fileName) {
+        LinkedList<String> jarFiles = null;
+        if ((jarFiles = indexMap.get(fileName)) == null) {
             /* try the package name again */
             int pos;
             if((pos = fileName.lastIndexOf("/")) != -1) {
-                jarFiles = (LinkedList)indexMap.get(fileName.substring(0, pos));
+                jarFiles = indexMap.get(fileName.substring(0, pos));
             }
         }
         return jarFiles;
@@ -200,23 +204,20 @@
             packageName = fileName;
         }
 
-        // add the mapping to indexMap
-        addToList(packageName, jarName, indexMap);
-
-        // add the mapping to jarMap
-        addToList(jarName, packageName, jarMap);
+        addMapping(packageName, jarName);
     }
 
     /**
      * Same as add(String,String) except that it doesn't strip off from the
-     * last index of '/'. It just adds the filename.
+     * last index of '/'. It just adds the jarItem (filename or package)
+     * as it is received.
      */
-    private void addExplicit(String fileName, String jarName) {
+    private void addMapping(String jarItem, String jarName) {
         // add the mapping to indexMap
-        addToList(fileName, jarName, indexMap);
+        addToList(jarItem, jarName, indexMap);
 
         // add the mapping to jarMap
-        addToList(jarName, fileName, jarMap);
+        addToList(jarName, jarItem, jarMap);
      }
 
     /**
@@ -235,9 +236,9 @@
             ZipFile zrf = new ZipFile(currentJar.replace
                                       ('/', File.separatorChar));
 
-            Enumeration entries = zrf.entries();
+            Enumeration<? extends ZipEntry> entries = zrf.entries();
             while(entries.hasMoreElements()) {
-                ZipEntry entry = (ZipEntry) entries.nextElement();
+                ZipEntry entry = entries.nextElement();
                 String fileName = entry.getName();
 
                 // Skip the META-INF directory, the index, and manifest.
@@ -247,18 +248,14 @@
                     fileName.equals(JarFile.MANIFEST_NAME))
                     continue;
 
-                if (!metaInfFilenames) {
+                if (!metaInfFilenames || !fileName.startsWith("META-INF/")) {
                     add(fileName, currentJar);
-                } else {
-                    if (!fileName.startsWith("META-INF/")) {
-                        add(fileName, currentJar);
-                    } else if (!entry.isDirectory()) {
+                } else if (!entry.isDirectory()) {
                         // Add files under META-INF explicitly so that certain
                         // services, like ServiceLoader, etc, can be located
                         // with greater accuracy. Directories can be skipped
                         // since each file will be added explicitly.
-                        addExplicit(fileName, currentJar);
-                    }
+                        addMapping(fileName, currentJar);
                 }
             }
 
@@ -282,11 +279,11 @@
                 /* print out the jar file name */
                 String jar = jarFiles[i];
                 bw.write(jar + "\n");
-                LinkedList jarlist = (LinkedList)jarMap.get(jar);
+                LinkedList<String> jarlist = jarMap.get(jar);
                 if (jarlist != null) {
-                    Iterator listitr = jarlist.iterator();
+                    Iterator<String> listitr = jarlist.iterator();
                     while(listitr.hasNext()) {
-                        bw.write((String)(listitr.next()) + "\n");
+                        bw.write(listitr.next() + "\n");
                     }
                 }
                 bw.write("\n");
@@ -309,7 +306,7 @@
         String currentJar = null;
 
         /* an ordered list of jar file names */
-        Vector jars = new Vector();
+        Vector<String> jars = new Vector<>();
 
         /* read until we see a .jar line */
         while((line = br.readLine()) != null && !line.endsWith(".jar"));
@@ -323,12 +320,11 @@
                 jars.add(currentJar);
             } else {
                 String name = line;
-                addToList(name, currentJar, indexMap);
-                addToList(currentJar, name, jarMap);
+                addMapping(name, currentJar);
             }
         }
 
-        jarFiles = (String[])jars.toArray(new String[jars.size()]);
+        jarFiles = jars.toArray(new String[jars.size()]);
     }
 
     /**
@@ -342,18 +338,18 @@
      *
      */
     public void merge(JarIndex toIndex, String path) {
-        Iterator itr = indexMap.entrySet().iterator();
+        Iterator<Map.Entry<String,LinkedList<String>>> itr = indexMap.entrySet().iterator();
         while(itr.hasNext()) {
-            Map.Entry e = (Map.Entry)itr.next();
-            String packageName = (String)e.getKey();
-            LinkedList from_list = (LinkedList)e.getValue();
-            Iterator listItr = from_list.iterator();
+            Map.Entry<String,LinkedList<String>> e = itr.next();
+            String packageName = e.getKey();
+            LinkedList<String> from_list = e.getValue();
+            Iterator<String> listItr = from_list.iterator();
             while(listItr.hasNext()) {
-                String jarName = (String)listItr.next();
+                String jarName = listItr.next();
                 if (path != null) {
                     jarName = path.concat(jarName);
                 }
-                toIndex.add(packageName, jarName);
+                toIndex.addMapping(packageName, jarName);
             }
         }
     }
diff --git a/ojluni/src/main/java/sun/misc/LRUCache.java b/ojluni/src/main/java/sun/misc/LRUCache.java
index d4b9554..8c14c17 100644
--- a/ojluni/src/main/java/sun/misc/LRUCache.java
+++ b/ojluni/src/main/java/sun/misc/LRUCache.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,7 +52,9 @@
 
     public V forName(N name) {
         if (oa == null) {
-            oa = (V[])new Object[size];
+            @SuppressWarnings("unchecked")
+            V[] temp = (V[])new Object[size];
+            oa = temp;
         } else {
             for (int i = 0; i < oa.length; i++) {
                 V ob = oa[i];
diff --git a/ojluni/src/main/java/sun/misc/MetaIndex.java b/ojluni/src/main/java/sun/misc/MetaIndex.java
index d2f7187..17481fb 100644
--- a/ojluni/src/main/java/sun/misc/MetaIndex.java
+++ b/ojluni/src/main/java/sun/misc/MetaIndex.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,7 +71,6 @@
 org/w3c/
 com/sun/imageio/
 javax/
-sunw/util/
 java/
 sun/
 ...
diff --git a/ojluni/src/main/java/sun/misc/REException.java b/ojluni/src/main/java/sun/misc/REException.java
index 1799e82..db68992 100644
--- a/ojluni/src/main/java/sun/misc/REException.java
+++ b/ojluni/src/main/java/sun/misc/REException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,9 @@
  */
 
 public class REException extends Exception {
+
+    private static final long serialVersionUID = 4656584872733646963L;
+
     REException (String s) {
         super(s);
     }
diff --git a/ojluni/src/main/java/sun/misc/SharedSecrets.java b/ojluni/src/main/java/sun/misc/SharedSecrets.java
index 0d0d744..d21aa4d 100644
--- a/ojluni/src/main/java/sun/misc/SharedSecrets.java
+++ b/ojluni/src/main/java/sun/misc/SharedSecrets.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
     for this purpose, namely the loss of compile-time checking. */
 
 public class SharedSecrets {
+    // BEGIN Android-changed: Pruned unused access interfaces
     private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
 
     public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiofda) {
@@ -44,4 +45,5 @@
     public static JavaIOFileDescriptorAccess getJavaIOFileDescriptorAccess() {
         return javaIOFileDescriptorAccess;
     }
+    // END Android-changed: 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 5414547..e9a89bc 100644
--- a/ojluni/src/main/java/sun/misc/URLClassPath.java
+++ b/ojluni/src/main/java/sun/misc/URLClassPath.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,7 @@
 import java.net.URLStreamHandler;
 import java.net.URLStreamHandlerFactory;
 import java.io.*;
+import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.AccessControlException;
 import java.security.CodeSigner;
@@ -53,6 +54,7 @@
 import java.security.cert.Certificate;
 import sun.misc.FileURLMapper;
 import sun.net.util.URLUtil;
+import sun.security.action.GetPropertyAction;
 
 /**
  * This class is used to maintain a search path of URLs for loading classes
@@ -64,16 +66,24 @@
     final static String USER_AGENT_JAVA_VERSION = "UA-Java-Version";
     final static String JAVA_VERSION;
     private static final boolean DEBUG;
+    private static final boolean DEBUG_LOOKUP_CACHE;
     private static final boolean DISABLE_JAR_CHECKING;
+    private static final boolean DISABLE_ACC_CHECKING;
 
     static {
         JAVA_VERSION = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("java.version"));
+            new GetPropertyAction("java.version"));
         DEBUG        = (java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.debug")) != null);
+            new GetPropertyAction("sun.misc.URLClassPath.debug")) != null);
+        DEBUG_LOOKUP_CACHE = (java.security.AccessController.doPrivileged(
+            new GetPropertyAction("sun.misc.URLClassPath.debugLookupCache")) != null);
         String p = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.disableJarChecking"));
+            new GetPropertyAction("sun.misc.URLClassPath.disableJarChecking"));
         DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
+
+        p = AccessController.doPrivileged(
+            new GetPropertyAction("jdk.net.URLClassPath.disableRestrictedPermissions"));
+        DISABLE_ACC_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
     }
 
     /* The original search path of URLs. */
@@ -94,6 +104,11 @@
     /* Whether this URLClassLoader has been closed yet */
     private boolean closed = false;
 
+    /* The context to be used when loading classes and resources.  If non-null
+     * this is the context that was captured during the creation of the
+     * URLClassLoader. null implies no additional security restrictions. */
+    private final AccessControlContext acc;
+
     /**
      * Creates a new URLClassPath for the given URLs. The URLs will be
      * searched in the order specified for classes and resources. A URL
@@ -103,8 +118,12 @@
      * @param urls the directory and JAR file URLs to search for classes
      *        and resources
      * @param factory the URLStreamHandlerFactory to use when creating new URLs
+     * @param acc the context to be used when loading classes and resources, may
+     *            be null
      */
-    public URLClassPath(URL[] urls, URLStreamHandlerFactory factory) {
+    public URLClassPath(URL[] urls,
+                        URLStreamHandlerFactory factory,
+                        AccessControlContext acc) {
         for (int i = 0; i < urls.length; i++) {
             path.add(urls[i]);
         }
@@ -112,10 +131,22 @@
         if (factory != null) {
             jarHandler = factory.createURLStreamHandler("jar");
         }
+        if (DISABLE_ACC_CHECKING)
+            this.acc = null;
+        else
+            this.acc = acc;
     }
 
+    /**
+     * Constructs a URLClassPath with no additional security restrictions.
+     * Used by code that implements the class path.
+     */
     public URLClassPath(URL[] urls) {
-        this(urls, null);
+        this(urls, null, null);
+    }
+
+    public URLClassPath(URL[] urls, AccessControlContext acc) {
+        this(urls, null, acc);
     }
 
     public synchronized List<IOException> closeLoaders() {
@@ -150,6 +181,12 @@
 
             urls.add(0, url);
             path.add(url);
+
+            if (lookupCacheURLs != null) {
+                // The lookup cache is no longer valid, since getLookupCache()
+                // does not consider the newly added url.
+                disableAllLookupCaches();
+            }
         }
     }
 
@@ -173,7 +210,8 @@
      */
     public URL findResource(String name, boolean check) {
         Loader loader;
-        for (int i = 0; (loader = getLoader(i)) != null; i++) {
+        int[] cache = getLookupCache(name);
+        for (int i = 0; (loader = getNextLoader(cache, i)) != null; i++) {
             URL url = loader.findResource(name, check);
             if (url != null) {
                 return url;
@@ -196,7 +234,8 @@
         }
 
         Loader loader;
-        for (int i = 0; (loader = getLoader(i)) != null; i++) {
+        int[] cache = getLookupCache(name);
+        for (int i = 0; (loader = getNextLoader(cache, i)) != null; i++) {
             Resource res = loader.getResource(name, check);
             if (res != null) {
                 return res;
@@ -216,6 +255,7 @@
                                      final boolean check) {
         return new Enumeration<URL>() {
             private int index = 0;
+            private int[] cache = getLookupCache(name);
             private URL url = null;
 
             private boolean next() {
@@ -223,7 +263,7 @@
                     return true;
                 } else {
                     Loader loader;
-                    while ((loader = getLoader(index++)) != null) {
+                    while ((loader = getNextLoader(cache, index++)) != null) {
                         url = loader.findResource(name, check);
                         if (url != null) {
                             return true;
@@ -263,6 +303,7 @@
                                     final boolean check) {
         return new Enumeration<Resource>() {
             private int index = 0;
+            private int[] cache = getLookupCache(name);
             private Resource res = null;
 
             private boolean next() {
@@ -270,7 +311,7 @@
                     return true;
                 } else {
                     Loader loader;
-                    while ((loader = getLoader(index++)) != null) {
+                    while ((loader = getNextLoader(cache, index++)) != null) {
                         res = loader.getResource(name, check);
                         if (res != null) {
                             return true;
@@ -299,6 +340,170 @@
         return getResources(name, true);
     }
 
+    private static volatile boolean lookupCacheEnabled
+    // Android-changed: No lookup cache support.
+    //    = "true".equals(VM.getSavedProperty("sun.cds.enableSharedLookupCache"));
+          = false;
+    private URL[] lookupCacheURLs;
+    private ClassLoader lookupCacheLoader;
+
+    synchronized void initLookupCache(ClassLoader loader) {
+        if ((lookupCacheURLs = getLookupCacheURLs(loader)) != null) {
+            lookupCacheLoader = loader;
+        } else {
+            // This JVM instance does not support lookup cache.
+            disableAllLookupCaches();
+        }
+    }
+
+    static void disableAllLookupCaches() {
+        lookupCacheEnabled = false;
+    }
+
+    // BEGIN Android-changed: No lookup chache support
+    /*
+    private static native URL[] getLookupCacheURLs(ClassLoader loader);
+    private static native int[] getLookupCacheForClassLoader(ClassLoader loader,
+                                                             String name);
+    private static native boolean knownToNotExist0(ClassLoader loader,
+                                                   String className);
+    */
+
+    private URL[] getLookupCacheURLs(ClassLoader loader) {
+        return null;
+    }
+    private static int[] getLookupCacheForClassLoader(ClassLoader loader,
+                                                      String name) {
+        return null;
+    }
+    private static boolean knownToNotExist0(ClassLoader loader,
+                                            String className) {
+        return false;
+    }
+    // END Android-changed: No lookup chache support
+
+
+    synchronized boolean knownToNotExist(String className) {
+        if (lookupCacheURLs != null && lookupCacheEnabled) {
+            return knownToNotExist0(lookupCacheLoader, className);
+        }
+
+        // Don't know if this class exists or not -- need to do a full search.
+        return false;
+    }
+
+    /**
+     * Returns an array of the index to lookupCacheURLs that may
+     * contain the specified resource. The values in the returned
+     * array are in strictly ascending order and must be a valid index
+     * to lookupCacheURLs array.
+     *
+     * This method returns an empty array if the specified resource
+     * cannot be found in this URLClassPath. If there is no lookup
+     * cache or it's disabled, this method returns null and the lookup
+     * should search the entire classpath.
+     *
+     * Example: if lookupCacheURLs contains {a.jar, b.jar, c.jar, d.jar}
+     * and package "foo" only exists in a.jar and c.jar,
+     * getLookupCache("foo/Bar.class") will return {0, 2}
+     *
+     * @param name the resource name
+     * @return an array of the index to lookupCacheURLs that may contain the
+     *         specified resource; or null if no lookup cache is used.
+     */
+    private synchronized int[] getLookupCache(String name) {
+        if (lookupCacheURLs == null || !lookupCacheEnabled) {
+            return null;
+        }
+
+        int[] cache = getLookupCacheForClassLoader(lookupCacheLoader, name);
+        if (cache != null && cache.length > 0) {
+            int maxindex = cache[cache.length - 1]; // cache[] is strictly ascending.
+            if (!ensureLoaderOpened(maxindex)) {
+                if (DEBUG_LOOKUP_CACHE) {
+                    System.out.println("Expanded loaders FAILED " +
+                                       loaders.size() + " for maxindex=" + maxindex);
+                }
+                return null;
+            }
+        }
+
+        return cache;
+    }
+
+    private boolean ensureLoaderOpened(int index) {
+        if (loaders.size() <= index) {
+            // Open all Loaders up to, and including, index
+            if (getLoader(index) == null) {
+                return false;
+            }
+            if (!lookupCacheEnabled) {
+                // cache was invalidated as the result of the above call.
+                return false;
+            }
+            if (DEBUG_LOOKUP_CACHE) {
+                System.out.println("Expanded loaders " + loaders.size() +
+                                   " to index=" + index);
+            }
+        }
+        return true;
+    }
+
+    /*
+     * The CLASS-PATH attribute was expanded by the VM when building
+     * the resource lookup cache in the same order as the getLoader
+     * method does. This method validates if the URL from the lookup
+     * cache matches the URL of the Loader at the given index;
+     * otherwise, this method disables the lookup cache.
+     */
+    private synchronized void validateLookupCache(int index,
+                                                  String urlNoFragString) {
+        if (lookupCacheURLs != null && lookupCacheEnabled) {
+            if (index < lookupCacheURLs.length &&
+                urlNoFragString.equals(
+                    URLUtil.urlNoFragString(lookupCacheURLs[index]))) {
+                return;
+            }
+            if (DEBUG || DEBUG_LOOKUP_CACHE) {
+                System.out.println("WARNING: resource lookup cache invalidated "
+                                   + "for lookupCacheLoader at " + index);
+            }
+            disableAllLookupCaches();
+        }
+    }
+
+    /**
+     * Returns the next Loader that may contain the resource to
+     * lookup. If the given cache is null, return loaders.get(index)
+     * that may be lazily created; otherwise, cache[index] is the next
+     * Loader that may contain the resource to lookup and so returns
+     * loaders.get(cache[index]).
+     *
+     * If cache is non-null, loaders.get(cache[index]) must be present.
+     *
+     * @param cache lookup cache. If null, search the entire class path
+     * @param index index to the given cache array; or to the loaders list.
+     */
+    private synchronized Loader getNextLoader(int[] cache, int index) {
+        if (closed) {
+            return null;
+        }
+        if (cache != null) {
+            if (index < cache.length) {
+                Loader loader = loaders.get(cache[index]);
+                if (DEBUG_LOOKUP_CACHE) {
+                    System.out.println("HASCACHE: Loading from : " + cache[index]
+                                       + " = " + loader.getBaseURL());
+                }
+                return loader;
+            } else {
+                return null; // finished iterating over cache[]
+            }
+        } else {
+            return getLoader(index);
+        }
+    }
+
     /*
      * Returns the Loader at the specified position in the URL search
      * path. The URLs are opened and expanded as needed. Returns null
@@ -340,11 +545,23 @@
             } catch (IOException e) {
                 // Silently ignore for now...
                 continue;
+            } catch (SecurityException se) {
+                // Always silently ignore. The context, if there is one, that
+                // this URLClassPath was given during construction will never
+                // have permission to access the URL.
+                if (DEBUG) {
+                    System.err.println("Failed to access " + url + ", " + se );
+                }
+                continue;
             }
             // Finally, add the Loader to the search path.
+            validateLookupCache(loaders.size(), urlNoFragString);
             loaders.add(loader);
             lmap.put(urlNoFragString, loader);
         }
+        if (DEBUG_LOOKUP_CACHE) {
+            System.out.println("NOCACHE: Loading from : " + index );
+        }
         return loaders.get(index);
     }
 
@@ -364,10 +581,10 @@
                             return new Loader(url);
                         }
                     } else {
-                        return new JarLoader(url, jarHandler, lmap);
+                        return new JarLoader(url, jarHandler, lmap, acc);
                     }
                 }
-            });
+            }, acc);
         } catch (java.security.PrivilegedActionException pae) {
             throw (IOException)pae.getException();
         }
@@ -513,7 +730,8 @@
                     }
                 } else {
                     // our best guess for the other cases
-                    InputStream is = url.openStream();
+                    uc.setUseCaches(false);
+                    InputStream is = uc.getInputStream();
                     is.close();
                 }
                 return url;
@@ -591,25 +809,31 @@
      */
     static class JarLoader extends Loader {
         private JarFile jar;
-        private URL csu;
+        private final URL csu;
         private JarIndex index;
         private MetaIndex metaIndex;
         private URLStreamHandler handler;
-        private HashMap<String, Loader> lmap;
+        private final HashMap<String, Loader> lmap;
+        private final AccessControlContext acc;
         private boolean closed = false;
+        // Android-changed: Not needed, called directly
+        // private static final sun.misc.JavaUtilZipFileAccess zipAccess =
+        //      sun.misc.SharedSecrets.getJavaUtilZipFileAccess();
 
         /*
          * Creates a new JarLoader for the specified URL referring to
          * a JAR file.
          */
         JarLoader(URL url, URLStreamHandler jarHandler,
-                  HashMap<String, Loader> loaderMap)
+                  HashMap<String, Loader> loaderMap,
+                  AccessControlContext acc)
             throws IOException
         {
             super(new URL("jar", "", -1, url + "!/", jarHandler));
             csu = url;
             handler = jarHandler;
             lmap = loaderMap;
+            this.acc = acc;
 
             if (!isOptimizable(url)) {
                 ensureOpen();
@@ -693,8 +917,7 @@
                                 }
                                 return null;
                             }
-                        }
-                    );
+                        }, acc);
                 } catch (java.security.PrivilegedActionException pae) {
                     throw (IOException)pae.getException();
                 }
@@ -739,7 +962,7 @@
             try {
                 ensureOpen();
             } catch (IOException e) {
-                throw (InternalError) new InternalError().initCause(e);
+                throw new InternalError(e);
             }
             return index;
         }
@@ -834,7 +1057,7 @@
             try {
                 ensureOpen();
             } catch (IOException e) {
-                throw (InternalError) new InternalError().initCause(e);
+                throw new InternalError(e);
             }
             final JarEntry entry = jar.getJarEntry(name);
             if (entry != null)
@@ -858,10 +1081,9 @@
                              Set<String> visited) {
 
             Resource res;
-            Object[] jarFiles;
-            boolean done = false;
+            String[] jarFiles;
             int count = 0;
-            LinkedList jarFilesList = null;
+            LinkedList<String> jarFilesList = null;
 
             /* If there no jar files in the index that can potential contain
              * this resource then return immediately.
@@ -870,11 +1092,11 @@
                 return null;
 
             do {
-                jarFiles = jarFilesList.toArray();
                 int size = jarFilesList.size();
+                jarFiles = jarFilesList.toArray(new String[size]);
                 /* loop through the mapped jar file list */
                 while(count < size) {
-                    String jarName = (String)jarFiles[count++];
+                    String jarName = jarFiles[count++];
                     JarLoader newLoader;
                     final URL url;
 
@@ -889,9 +1111,9 @@
                                 new PrivilegedExceptionAction<JarLoader>() {
                                     public JarLoader run() throws IOException {
                                         return new JarLoader(url, handler,
-                                            lmap);
+                                            lmap, acc);
                                     }
-                                });
+                                }, acc);
 
                             /* this newly opened jar file has its own index,
                              * merge it into the parent's index, taking into
@@ -922,7 +1144,7 @@
                         try {
                             newLoader.ensureOpen();
                         } catch (IOException e) {
-                            throw (InternalError) new InternalError().initCause(e);
+                            throw new InternalError(e);
                         }
                         final JarEntry entry = newLoader.jar.getJarEntry(name);
                         if (entry != null) {
@@ -999,6 +1221,8 @@
          * parse the standard extension dependencies
          */
         private void  parseExtensionsDependencies() throws IOException {
+            // Android-changed: checkExtensionsDependencies(jar) is not supported on Android.
+            //ExtensionDependency.checkExtensionsDependencies(jar);
         }
 
         /*
diff --git a/ojluni/src/main/java/sun/misc/VM.java b/ojluni/src/main/java/sun/misc/VM.java
index b57eb4a..f9060ba 100644
--- a/ojluni/src/main/java/sun/misc/VM.java
+++ b/ojluni/src/main/java/sun/misc/VM.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,7 @@
         return suspended;
     }
 
+    @SuppressWarnings("deprecation")
     public static boolean allowThreadSuspension(ThreadGroup g, boolean b) {
         return g.allowThreadSuspension(b);
     }
@@ -92,6 +93,11 @@
         return STATE_GREEN;
     }
 
+    // Android-removed: Not used
+    /** @deprecated */
+    // @Deprecated
+    // public static void registerVMNotification(VMNotification n) { }
+
     /** @deprecated */
     @Deprecated
     public static void asChange(int as_old, int as_new) { }
@@ -143,6 +149,7 @@
 
 
     private static volatile boolean booted = false;
+    private static final Object lock = new Object();
 
     // Invoked by by System.initializeSystemClass just before returning.
     // Subsystems that are invoked during initialization can check this
@@ -150,20 +157,34 @@
     // application class loader has been set up.
     //
     public static void booted() {
-        booted = true;
+        synchronized (lock) {
+            booted = true;
+            lock.notifyAll();
+        }
     }
 
     public static boolean isBooted() {
         return booted;
     }
 
+    // Waits until VM completes initialization
+    //
+    // This method is invoked by the Finalizer thread
+    public static void awaitBooted() throws InterruptedException {
+        synchronized (lock) {
+            while (!booted) {
+                lock.wait();
+            }
+        }
+    }
+
     // A user-settable upper limit on the maximum amount of allocatable direct
     // buffer memory.  This value may be changed during VM initialization if
     // "java" is launched with "-XX:MaxDirectMemorySize=<size>".
     //
     // The initial value of this field is arbitrary; during JRE initialization
     // it will be reset to the value specified on the command line, if any,
-    // otherwise to Runtime.getRuntime.maxDirectMemory().
+    // otherwise to Runtime.getRuntime().maxMemory().
     //
     private static long directMemory = 64 * 1024 * 1024;
 
@@ -212,16 +233,15 @@
         return allowArraySyntax;
     }
 
-    private static boolean allowGetCallerClass = true;
-
-    // Reflection.getCallerClass(int) is enabled by default.
-    // It can be disabled by setting the system property
-    // "jdk.reflect.allowGetCallerClass" to "false". It cannot be
-    // disabled if the logging stack walk (to find resource bundles)
-    // is enabled.
-    public static boolean allowGetCallerClass() {
-        return allowGetCallerClass;
-    }
+    // 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.
+     */
+    // public static boolean isSystemDomainLoader(ClassLoader loader) {
+    //     return loader == null;
+    // }
+    // END Android-removed: Not used on android
 
     /**
      * Returns the system property of the specified key saved at
@@ -288,15 +308,6 @@
                                ? defaultAllowArraySyntax
                                : Boolean.parseBoolean(s));
 
-        // Reflection.getCallerClass(int) is enabled by default.
-        // It can be disabled by setting a system property (but only if
-        // the logging stack walk is not enabled)
-        s = props.getProperty("jdk.reflect.allowGetCallerClass");
-        allowGetCallerClass = (s != null
-                                   ? (s.isEmpty() || Boolean.parseBoolean(s))
-                                   : true) ||
-             Boolean.parseBoolean(props.getProperty("jdk.logging.allowStackWalkSearch"));
-
         // Remove other private system properties
         // used by java.lang.Integer.IntegerCache
         props.remove("java.lang.Integer.IntegerCache.high");
@@ -306,12 +317,19 @@
 
         // used by sun.launcher.LauncherHelper
         props.remove("sun.java.launcher.diag");
+
+        // used by sun.misc.URLClassPath
+        props.remove("sun.cds.enableSharedLookupCache");
     }
 
     // Initialize any miscellenous operating system settings that need to be
     // set for the class libraries.
     //
     public static void initializeOSEnvironment() {
+        // Android-removed: OSEnvironment.initialize() not supported
+        //if (!booted) {
+        //    OSEnvironment.initialize();
+        //}
     }
 
     /* Current count of objects pending for finalization */
@@ -384,4 +402,17 @@
     private final static int JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400;
     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
+    // /*
+    //  * 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.
+    //  */
+    // public static native ClassLoader latestUserDefinedLoader();
+
+    // static {
+    //     initialize();
+    // }
+    // private native static void initialize();
+    // END Android-removed: latestUserDefinedLoader()/initialize() not supported
 }
diff --git a/ojluni/src/main/java/sun/misc/Version.java b/ojluni/src/main/java/sun/misc/Version.java
index 6ea3823..3ac6a91 100644
--- a/ojluni/src/main/java/sun/misc/Version.java
+++ b/ojluni/src/main/java/sun/misc/Version.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
     private static final String launcher_name = "";
     private static final String java_version = AndroidHardcodedSystemProperties.JAVA_VERSION;
     private static final String java_runtime_name = "Android Runtime";
+    private static final String java_profile_name = "";
     private static final String java_runtime_version = "0.9";
 
     // Called by java.lang.System.<clinit>
@@ -81,23 +82,28 @@
         boolean isHeadless = false;
 
         /* Report that we're running headless if the property is true */
-	String headless = System.getProperty("java.awt.headless");
-	if ( (headless != null) && (headless.equalsIgnoreCase("true")) ) {
+        String headless = System.getProperty("java.awt.headless");
+        if ( (headless != null) && (headless.equalsIgnoreCase("true")) ) {
             isHeadless = true;
-	}
+        }
 
         /* First line: platform version. */
         ps.println(launcher_name + " version \"" + java_version + "\"");
 
         /* Second line: runtime version (ie, libraries). */
 
-	ps.print(java_runtime_name + " (build " + java_runtime_version);
+        ps.print(java_runtime_name + " (build " + java_runtime_version);
 
-	if (java_runtime_name.indexOf("Embedded") != -1 && isHeadless) {
-	    // embedded builds report headless state
-	    ps.print(", headless");
-	}
-	ps.println(')');
+        if (java_profile_name.length() > 0) {
+            // profile name
+            ps.print(", profile " + java_profile_name);
+        }
+
+        if (java_runtime_name.indexOf("Embedded") != -1 && isHeadless) {
+            // embedded builds report headless state
+            ps.print(", headless");
+        }
+        ps.println(')');
 
         /* Third line: JVM information. */
         String java_vm_name    = System.getProperty("java.vm.name");
@@ -274,15 +280,24 @@
                 jvm_minor_version = Character.digit(cs.charAt(2), 10);
                 jvm_micro_version = Character.digit(cs.charAt(4), 10);
                 cs = cs.subSequence(5, cs.length());
-                if (cs.charAt(0) == '_' && cs.length() >= 3 &&
-                    Character.isDigit(cs.charAt(1)) &&
-                    Character.isDigit(cs.charAt(2))) {
-                    int nextChar = 3;
+                if (cs.charAt(0) == '_' && cs.length() >= 3) {
+                    int nextChar = 0;
+                    if (Character.isDigit(cs.charAt(1)) &&
+                        Character.isDigit(cs.charAt(2)) &&
+                        Character.isDigit(cs.charAt(3)))
+                    {
+                        nextChar = 4;
+                    } else if (Character.isDigit(cs.charAt(1)) &&
+                        Character.isDigit(cs.charAt(2)))
+                    {
+                        nextChar = 3;
+                    }
+
                     try {
-                        String uu = cs.subSequence(1, 3).toString();
-                        jvm_update_version = Integer.parseInt(uu);
-                        if (cs.length() >= 4) {
-                            char c = cs.charAt(3);
+                        String uu = cs.subSequence(1, nextChar).toString();
+                        jvm_update_version = Integer.valueOf(uu).intValue();
+                        if (cs.length() >= nextChar + 1) {
+                            char c = cs.charAt(nextChar);
                             if (c >= 'a' && c <= 'z') {
                                 jvm_special_version = Character.toString(c);
                                 nextChar++;
@@ -305,7 +320,7 @@
                             Character.isDigit(s.charAt(1)) &&
                             Character.isDigit(s.charAt(2))) {
                             jvm_build_number =
-                                Integer.parseInt(s.substring(1, 3));
+                                Integer.valueOf(s.substring(1, 3)).intValue();
                             break;
                         }
                     }
@@ -322,7 +337,6 @@
     // Return false if not available which implies an old VM (Tiger or before).
     private static native boolean getJvmVersionInfo();
     private static native void getJdkVersionInfo();
-
 }
 
 // Help Emacs a little because this file doesn't end in .java.
diff --git a/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java b/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java
index 94005e0..0b58a99 100644
--- a/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java
+++ b/ojluni/src/main/java/sun/net/ExtendedOptionsImpl.java
@@ -43,6 +43,17 @@
  */
 public class ExtendedOptionsImpl {
 
+    // Android-removed: System.loadLibrary("net") is not available on Android.
+    /*
+    static {
+        AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
+            System.loadLibrary("net");
+            return null;
+        });
+        init();
+    }
+    */
+
     private ExtendedOptionsImpl() {}
 
     public static void checkSetOptionPermission(SocketOption<?> option) {
@@ -71,6 +82,9 @@
         }
     }
 
+    // Android-removed: Native initialization logic that doesn't exist on Android.
+    // private static native void init();
+
     /*
      * Extension native implementations
      *
diff --git a/ojluni/src/main/java/sun/net/NetHooks.java b/ojluni/src/main/java/sun/net/NetHooks.java
index 05100d9..153096e 100644
--- a/ojluni/src/main/java/sun/net/NetHooks.java
+++ b/ojluni/src/main/java/sun/net/NetHooks.java
@@ -38,43 +38,45 @@
 
 public final class NetHooks {
 
-    // Android-removed: No SDP support.
-    // /**
-    //  * A provider with hooks to allow sockets be converted prior to binding or
-    //  * connecting a TCP socket.
-    //  *
-    //  * <p> Concrete implementations of this class should define a zero-argument
-    //  * constructor and implement the abstract methods specified below.
-    //  */
-    //  public static abstract class Provider {
-    //     /**
-    //      * Initializes a new instance of this class.
-    //      */
-    //     protected Provider() {}
-    //
-    //    /**
-    //      * Invoked prior to binding a TCP socket.
-    //      */
-    //     public abstract void implBeforeTcpBind(FileDescriptor fdObj,
-    //                                            InetAddress address,
-    //                                            int port)
-    //         throws IOException;
-    //
-    //     /**
-    //      * Invoked prior to connecting an unbound TCP socket.
-    //      */
-    //     public abstract void implBeforeTcpConnect(FileDescriptor fdObj,
-    //                                              InetAddress address,
-    //                                              int port)
-    //         throws IOException;
-    // }
+    // Android-removed: Android doesn't support Session Description Protocol (SDP).
+    /*
+    /**
+     * A provider with hooks to allow sockets be converted prior to binding or
+     * connecting a TCP socket.
+     *
+     * <p> Concrete implementations of this class should define a zero-argument
+     * constructor and implement the abstract methods specified below.
+     *
+    public static abstract class Provider {
+        /**
+         * Initializes a new instance of this class.
+         *
+        protected Provider() {}
+
+        /**
+         * Invoked prior to binding a TCP socket.
+         *
+        public abstract void implBeforeTcpBind(FileDescriptor fdObj,
+                                               InetAddress address,
+                                               int port)
+            throws IOException;
+
+        /**
+         * Invoked prior to connecting an unbound TCP socket.
+         *
+        public abstract void implBeforeTcpConnect(FileDescriptor fdObj,
+                                                 InetAddress address,
+                                                 int port)
+            throws IOException;
+    }
+    */
 
     /**
      * For now, we load the SDP provider on Solaris. In the future this may
      * be changed to use the ServiceLoader facility to allow the deployment of
      * other providers.
      */
-    // Android-removed: No SDP support
+    // Android-removed: Android doesn't support Session Description Protocol (SDP).
     // private static final Provider provider = new sun.net.sdp.SdpProvider();
 
     /**
@@ -85,7 +87,7 @@
                                      int port)
         throws IOException
     {
-        // Android-removed: No SDP support
+        // Android-removed: Android doesn't support Session Description Protocol (SDP).
         // provider.implBeforeTcpBind(fdObj, address, port);
     }
 
diff --git a/ojluni/src/main/java/sun/net/NetworkClient.java b/ojluni/src/main/java/sun/net/NetworkClient.java
index 1b311bc..0f76bf6 100644
--- a/ojluni/src/main/java/sun/net/NetworkClient.java
+++ b/ojluni/src/main/java/sun/net/NetworkClient.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -139,7 +139,7 @@
                                         serverSocket.getOutputStream()),
                                         true, encoding);
         } catch (UnsupportedEncodingException e) {
-            throw new InternalError(encoding +"encoding not found");
+            throw new InternalError(encoding +"encoding not found", e);
         }
         serverInput = new BufferedInputStream(serverSocket.getInputStream());
     }
@@ -244,7 +244,7 @@
      * Sets the read timeout.
      *
      * Note: Public URLConnection (and protocol specific implementations)
-     * protect against negative timeout values being set. This implemenation,
+     * protect against negative timeout values being set. This implementation,
      * and protocol specific implementations, use -1 to represent the default
      * read timeout.
      *
diff --git a/ojluni/src/main/java/sun/net/TelnetOutputStream.java b/ojluni/src/main/java/sun/net/TelnetOutputStream.java
index 432e975..74f6c9c 100644
--- a/ojluni/src/main/java/sun/net/TelnetOutputStream.java
+++ b/ojluni/src/main/java/sun/net/TelnetOutputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -81,7 +81,7 @@
     }
 
     /**
-     * set the stickyCRLF flag. Tells wether the terminal considers CRLF as a single
+     * set the stickyCRLF flag. Tells whether the terminal considers CRLF as a single
      * char.
      *
      * @param   on      the <code>boolean</code> to set the flag to.
diff --git a/ojluni/src/main/java/sun/net/ftp/FtpClient.java b/ojluni/src/main/java/sun/net/ftp/FtpClient.java
index 3e9f385..73df120 100644
--- a/ojluni/src/main/java/sun/net/ftp/FtpClient.java
+++ b/ojluni/src/main/java/sun/net/ftp/FtpClient.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -267,7 +267,7 @@
      * @param user The user name
      * @param password The password for that user
      * @return this FtpClient
-     * @throws IOException if an error occured during the transmission
+     * @throws IOException if an error occurred during the transmission
      * @throws FtpProtocolException if the login was refused by the server
      */
     public abstract FtpClient login(String user, char[] password) throws FtpProtocolException, IOException;
@@ -378,7 +378,7 @@
      *
      * @param name the name of the remote file
      * @return the {@link java.io.InputStream} from the data connection
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was refused by the server
      * @see #setRestartOffset(long)
      */
@@ -398,7 +398,7 @@
      * @param name the name of the remote file to write.
      * @return the {@link java.io.OutputStream} from the data connection or
      *         {@code null} if the command was unsuccessful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public OutputStream putFileStream(String name) throws FtpProtocolException, IOException {
@@ -427,7 +427,7 @@
      * @param unique {@code true} if the remote files should be unique,
      *        in which case the STOU command will be used.
      * @return the {@link java.io.OutputStream} from the data connection.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract OutputStream putFileStream(String name, boolean unique) throws FtpProtocolException, IOException;
@@ -456,7 +456,7 @@
      * @param local the {@code InputStream} that points to the data to
      *        transfer.
      * @return this FtpClient
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public FtpClient putFile(String name, InputStream local) throws FtpProtocolException, IOException {
@@ -481,7 +481,7 @@
      * @param unique {@code true} if the remote file should be unique
      *        (i.e. not already existing), {@code false} otherwise.
      * @return this FtpClient
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      * @see #getLastFileName()
      */
@@ -500,7 +500,7 @@
      * @param local The {@code InputStream} providing access to the data
      *        to be appended.
      * @return this FtpClient
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient appendFile(String name, InputStream local) throws FtpProtocolException, IOException;
@@ -511,7 +511,7 @@
      * @param from the name of the file being renamed
      * @param to the new name for the file
      * @return this FtpClient
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient rename(String from, String to) throws FtpProtocolException, IOException;
@@ -522,7 +522,7 @@
      * @param name a {@code String} containing the name of the file
      *        to delete.
      * @return this FtpClient
-     * @throws IOException if an error occured during the exchange
+     * @throws IOException if an error occurred during the exchange
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient deleteFile(String name) throws FtpProtocolException, IOException;
@@ -533,7 +533,7 @@
      * @param name a {@code String} containing the name of the directory
      *        to create.
      * @return this FtpClient
-     * @throws IOException if an error occured during the exchange
+     * @throws IOException if an error occurred during the exchange
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient makeDirectory(String name) throws FtpProtocolException, IOException;
@@ -545,7 +545,7 @@
      *        to remove.
      *
      * @return this FtpClient
-     * @throws IOException if an error occured during the exchange.
+     * @throws IOException if an error occurred during the exchange.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient removeDirectory(String name) throws FtpProtocolException, IOException;
@@ -555,7 +555,7 @@
      * status or as a <I>keep alive</I> mechanism.
      *
      * @return this FtpClient
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient noop() throws FtpProtocolException, IOException;
@@ -572,7 +572,7 @@
      * @param name an optional {@code String} containing the pathname
      *        the STAT command should apply to.
      * @return the response from the server
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract String getStatus(String name) throws FtpProtocolException, IOException;
@@ -602,7 +602,7 @@
      * after an abort.</p>
      *
      * @return this FtpClient
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient abort() throws FtpProtocolException, IOException;
@@ -637,7 +637,7 @@
      * </pre>
      * <p>Since {@link #close()} will call completePending() if necessary.</p>
      * @return this FtpClient
-     * @throws IOException if an error occured during the transfer
+     * @throws IOException if an error occurred during the transfer
      * @throws FtpProtocolException if the command didn't complete successfully
      */
     public abstract FtpClient completePending() throws FtpProtocolException, IOException;
@@ -786,7 +786,7 @@
      *        for the current working directoty.
      * @return a {@code Iterator} of files or {@code null} if the
      *         command failed.
-     * @throws IOException if an error occured during the transmission
+     * @throws IOException if an error occurred during the transmission
      * @see #setDirParser(FtpDirParser)
      * @see #changeDirectory(String)
      * @throws FtpProtocolException if the command was rejected by the server
@@ -862,7 +862,7 @@
      * but before calling {@link #login(java.lang.String, char[]) }.</p>
      *
      * @return this FtpCLient
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      * @see #endSecureSession()
      */
@@ -874,7 +874,7 @@
      * back to a non encrypted transmission.
      *
      * @return this FtpClient
-     * @throws IOException if an error occured during transmission.
+     * @throws IOException if an error occurred during transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      * @see #startSecureSession()
      */
@@ -886,7 +886,7 @@
      *
      * @param size The number of bytes to allocate.
      * @return this FtpClient
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient allocate(long size) throws FtpProtocolException, IOException;
@@ -899,7 +899,7 @@
      * @param struct a {@code String} containing the name of the
      *        structure to mount.
      * @return this FtpClient
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient structureMount(String struct) throws FtpProtocolException, IOException;
@@ -911,7 +911,7 @@
      *
      * @return a {@code String} describing the OS, or {@code null}
      *         if the operation was not successful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract String getSystem() throws FtpProtocolException, IOException;
@@ -924,7 +924,7 @@
      *        {@code null} for the general help
      * @return a {@code String} containing the text sent back by the
      *         server, or {@code null} if the command failed.
-     * @throws IOException if an error occured during transmission
+     * @throws IOException if an error occurred during transmission
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract String getHelp(String cmd) throws FtpProtocolException, IOException;
@@ -936,7 +936,7 @@
      *
      * @param cmd the command to be sent.
      * @return this FtpClient
-     * @throws IOException if an error occured during transmission
+     * @throws IOException if an error occurred during transmission
      * @throws FtpProtocolException if the command was rejected by the server
      */
     public abstract FtpClient siteCmd(String cmd) throws FtpProtocolException, IOException;
diff --git a/ojluni/src/main/java/sun/net/ftp/FtpClientProvider.java b/ojluni/src/main/java/sun/net/ftp/FtpClientProvider.java
index 71cd134..06deae6 100644
--- a/ojluni/src/main/java/sun/net/ftp/FtpClientProvider.java
+++ b/ojluni/src/main/java/sun/net/ftp/FtpClientProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ServiceConfigurationError;
-//import sun.misc.Service;
+//import java.util.ServiceLoader;
 
 /**
  * Service provider class for FtpClient.
@@ -67,35 +67,34 @@
             return false;
         }
         try {
-            Class c = Class.forName(cm, true, null);
+            Class<?> c = Class.forName(cm, true, null);
             provider = (FtpClientProvider) c.newInstance();
             return true;
-        } catch (ClassNotFoundException x) {
-            throw new ServiceConfigurationError(x.toString());
-        } catch (IllegalAccessException x) {
-            throw new ServiceConfigurationError(x.toString());
-        } catch (InstantiationException x) {
-            throw new ServiceConfigurationError(x.toString());
-        } catch (SecurityException x) {
+        } catch (ClassNotFoundException |
+                 IllegalAccessException |
+                 InstantiationException |
+                 SecurityException x) {
             throw new ServiceConfigurationError(x.toString());
         }
     }
 
     private static boolean loadProviderAsService() {
-        //        Iterator i = Service.providers(FtpClientProvider.class,
-        //                ClassLoader.getSystemClassLoader());
-        //        while (i.hasNext()) {
-        //            try {
-        //                provider = (FtpClientProvider) i.next();
-        //                return true;
-        //            } catch (ServiceConfigurationError sce) {
-        //                if (sce.getCause() instanceof SecurityException) {
-        //                    // Ignore, try next provider, if any
-        //                    continue;
-        //                }
-        //                throw sce;
-        //            }
-        //        }
+//        Iterator<FtpClientProvider> i =
+//                ServiceLoader.load(FtpClientProvider.class,
+//                                   ClassLoader.getSystemClassLoader()).iterator();
+//
+//        while (i.hasNext()) {
+//            try {
+//                provider = i.next();
+//                return true;
+//            } catch (ServiceConfigurationError sce) {
+//                if (sce.getCause() instanceof SecurityException) {
+//                    // Ignore, try next provider, if any
+//                    continue;
+//                }
+//                throw sce;
+//            }
+//        }
         return false;
     }
 
diff --git a/ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java b/ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java
index fea9421..0c117d4 100644
--- a/ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java
+++ b/ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java
@@ -28,7 +28,6 @@
 import java.io.*;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.security.PrivilegedExceptionAction;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -431,7 +430,7 @@
             }
             response = replyBuf.toString();
             replyBuf.setLength(0);
-            if (logger.isLoggable(PlatformLogger.FINEST)) {
+            if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
                 logger.finest("Server [" + serverAddr + "] --> " + response);
             }
 
@@ -473,7 +472,7 @@
     /** Sends command <i>cmd</i> to the server. */
     private void sendServer(String cmd) {
         out.print(cmd);
-        if (logger.isLoggable(PlatformLogger.FINEST)) {
+        if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
             logger.finest("Server [" + serverAddr + "] <-- " + cmd);
         }
     }
@@ -492,7 +491,7 @@
      * Read the reply from the FTP server.
      *
      * @return <code>true</code> if the command was successful
-     * @throws IOException if an error occured
+     * @throws IOException if an error occurred
      */
     private boolean readReply() throws IOException {
         lastReplyCode = FtpReplyCode.find(readServerResponse());
@@ -545,7 +544,7 @@
      *
      * @param cmd String containing the command
      *
-     * @throws FtpProtocolException if an error occured
+     * @throws FtpProtocolException if an error occurred
      */
     private void issueCommandCheck(String cmd) throws sun.net.ftp.FtpProtocolException, IOException {
         if (!issueCommand(cmd)) {
@@ -668,7 +667,6 @@
         // Bind the socket to the same address as the control channel. This
         // is needed in case of multi-homed systems.
         s.bind(new InetSocketAddress(serverAddress, 0));
-
         if (connectTimeout >= 0) {
             s.connect(dest, connectTimeout);
         } else {
@@ -747,7 +745,7 @@
             // Some FTP servers (like the one on Solaris) are bugged, they
             // will accept the EPRT command but then, the subsequent command
             // (e.g. RETR) will fail, so we have to check BOTH results (the
-            // EPRT cmd then the actual command) to decide wether we should
+            // EPRT cmd then the actual command) to decide whether we should
             // fall back on the older PORT command.
             portCmd = "EPRT |" + ((myAddress instanceof Inet6Address) ? "2" : "1") + "|" +
                     myAddress.getHostAddress() + "|" + portSocket.getLocalPort() + "|";
@@ -837,6 +835,7 @@
      * @see #setActiveMode()
      */
     public sun.net.ftp.FtpClient enablePassiveMode(boolean passive) {
+
         // Only passive mode used in JDK. See Bug 8010784.
         // passiveMode = passive;
         return this;
@@ -927,7 +926,7 @@
             out = new PrintStream(new BufferedOutputStream(server.getOutputStream()),
                     true, encoding);
         } catch (UnsupportedEncodingException e) {
-            throw new InternalError(encoding + "encoding not found");
+            throw new InternalError(encoding + "encoding not found", e);
         }
         in = new BufferedInputStream(server.getInputStream());
     }
@@ -1045,7 +1044,7 @@
      * @param user The user name
      * @param password The password for that user
      * @return <code>true</code> if the login was successful.
-     * @throws IOException if an error occured during the transmission
+     * @throws IOException if an error occurred during the transmission
      */
     public sun.net.ftp.FtpClient login(String user, char[] password) throws sun.net.ftp.FtpProtocolException, IOException {
         if (!isConnected()) {
@@ -1273,7 +1272,7 @@
      * @param name the name of the remote file
      * @return the {@link java.io.InputStream} from the data connection, or
      *         <code>null</code> if the command was unsuccessful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      */
     public InputStream getFileStream(String name) throws sun.net.ftp.FtpProtocolException, IOException {
         Socket s;
@@ -1322,7 +1321,7 @@
      *        in which case the STOU command will be used.
      * @return the {@link java.io.OutputStream} from the data connection or
      *         <code>null</code> if the command was unsuccessful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      */
     public OutputStream putFileStream(String name, boolean unique)
         throws sun.net.ftp.FtpProtocolException, IOException
@@ -1351,7 +1350,7 @@
      * @param unique <code>true</code> if the remote file should be unique
      *        (i.e. not already existing), <code>false</code> otherwise.
      * @return <code>true</code> if the transfer was successful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @see #getLastFileName()
      */
     public sun.net.ftp.FtpClient putFile(String name, InputStream local, boolean unique) throws sun.net.ftp.FtpProtocolException, IOException {
@@ -1382,7 +1381,7 @@
      * @param local The <code>InputStream</code> providing access to the data
      *        to be appended.
      * @return <code>true</code> if the transfer was successful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      */
     public sun.net.ftp.FtpClient appendFile(String name, InputStream local) throws sun.net.ftp.FtpProtocolException, IOException {
         int mtu = 1500;
@@ -1418,7 +1417,7 @@
      * @param name a <code>String</code> containing the name of the file
      *        to delete.
      * @return <code>true</code> if the command was successful
-     * @throws IOException if an error occured during the exchange
+     * @throws IOException if an error occurred during the exchange
      */
     public sun.net.ftp.FtpClient deleteFile(String name) throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck("DELE " + name);
@@ -1431,7 +1430,7 @@
      * @param name a <code>String</code> containing the name of the directory
      *        to create.
      * @return <code>true</code> if the operation was successful.
-     * @throws IOException if an error occured during the exchange
+     * @throws IOException if an error occurred during the exchange
      */
     public sun.net.ftp.FtpClient makeDirectory(String name) throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck("MKD " + name);
@@ -1445,7 +1444,7 @@
      *        to remove.
      *
      * @return <code>true</code> if the operation was successful.
-     * @throws IOException if an error occured during the exchange.
+     * @throws IOException if an error occurred during the exchange.
      */
     public sun.net.ftp.FtpClient removeDirectory(String name) throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck("RMD " + name);
@@ -1476,7 +1475,7 @@
      *        the STAT command should apply to.
      * @return the response from the server or <code>null</code> if the
      *         command failed.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      */
     public String getStatus(String name) throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck((name == null ? "STAT" : "STAT " + name));
@@ -1559,7 +1558,7 @@
      * It tells the server to stop the previous command or transfer.
      *
      * @return <code>true</code> if the command was successful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      */
     public sun.net.ftp.FtpClient abort() throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck("ABOR");
@@ -1646,7 +1645,7 @@
                     out = new PrintStream(new BufferedOutputStream(server.getOutputStream()),
                             true, encoding);
                 } catch (UnsupportedEncodingException e) {
-                    throw new InternalError(encoding + "encoding not found");
+                    throw new InternalError(encoding + "encoding not found", e);
                 }
                 in = new BufferedInputStream(server.getInputStream());
             }
@@ -1719,7 +1718,7 @@
      */
     public InputStream nameList(String path) throws sun.net.ftp.FtpProtocolException, IOException {
         Socket s;
-        s = openDataConnection("NLST " + path);
+        s = openDataConnection(path == null ? "NLST" : "NLST " + path);
         if (s != null) {
             return createInputStream(s.getInputStream());
         }
@@ -1882,7 +1881,7 @@
      *        for the current working directoty.
      * @return a <code>Iterator</code> of files or <code>null</code> if the
      *         command failed.
-     * @throws IOException if an error occured during the transmission
+     * @throws IOException if an error occurred during the transmission
      * @see #setDirParser(FtpDirParser)
      * @see #changeDirectory(String)
      */
@@ -2050,7 +2049,7 @@
      * {@link #reInit()} command or a {@link #endSecureSession()} command is issued.
      *
      * @return <code>true</code> if the operation was successful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      * @see #endSecureSession()
      */
     public sun.net.ftp.FtpClient startSecureSession() throws sun.net.ftp.FtpProtocolException, IOException {
@@ -2082,7 +2081,7 @@
             out = new PrintStream(new BufferedOutputStream(server.getOutputStream()),
                     true, encoding);
         } catch (UnsupportedEncodingException e) {
-            throw new InternalError(encoding + "encoding not found");
+            throw new InternalError(encoding + "encoding not found", e);
         }
         in = new BufferedInputStream(server.getInputStream());
 
@@ -2098,7 +2097,7 @@
      * back to a non crypted transmission.
      *
      * @return <code>true</code> if the operation was successful.
-     * @throws IOException if an error occured during transmission.
+     * @throws IOException if an error occurred during transmission.
      * @see #startSecureSession()
      */
     public sun.net.ftp.FtpClient endSecureSession() throws sun.net.ftp.FtpProtocolException, IOException {
@@ -2116,7 +2115,7 @@
             out = new PrintStream(new BufferedOutputStream(server.getOutputStream()),
                     true, encoding);
         } catch (UnsupportedEncodingException e) {
-            throw new InternalError(encoding + "encoding not found");
+            throw new InternalError(encoding + "encoding not found", e);
         }
         in = new BufferedInputStream(server.getInputStream());
 
@@ -2129,7 +2128,7 @@
      *
      * @param size The number of bytes to allocate.
      * @return <code>true</code> if the operation was successful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      */
     public sun.net.ftp.FtpClient allocate(long size) throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck("ALLO " + size);
@@ -2144,7 +2143,7 @@
      * @param struct a <code>String</code> containing the name of the
      *        structure to mount.
      * @return <code>true</code> if the operation was successful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      */
     public sun.net.ftp.FtpClient structureMount(String struct) throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck("SMNT " + struct);
@@ -2158,7 +2157,7 @@
      *
      * @return a <code>String</code> describing the OS, or <code>null</code>
      *         if the operation was not successful.
-     * @throws IOException if an error occured during the transmission.
+     * @throws IOException if an error occurred during the transmission.
      */
     public String getSystem() throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck("SYST");
@@ -2178,7 +2177,7 @@
      *        <code>null</code> for the general help
      * @return a <code>String</code> containing the text sent back by the
      *         server, or <code>null</code> if the command failed.
-     * @throws IOException if an error occured during transmission
+     * @throws IOException if an error occurred during transmission
      */
     public String getHelp(String cmd) throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck("HELP " + cmd);
@@ -2221,7 +2220,7 @@
      *
      * @param cmd the command to be sent.
      * @return <code>true</code> if the command was successful.
-     * @throws IOException if an error occured during transmission
+     * @throws IOException if an error occurred during transmission
      */
     public sun.net.ftp.FtpClient siteCmd(String cmd) throws sun.net.ftp.FtpProtocolException, IOException {
         issueCommandCheck("SITE " + cmd);
diff --git a/ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java b/ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java
index 6ba9b9a..fac57e2 100644
--- a/ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java
+++ b/ojluni/src/main/java/sun/net/spi/DefaultProxySelector.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,13 +33,14 @@
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.StringTokenizer;
 import java.io.IOException;
-import sun.misc.RegexpPool;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.StringJoiner;
+import java.util.regex.Pattern;
 import sun.net.NetProperties;
 import sun.net.SocksProxy;
+import static java.util.regex.Pattern.quote;
 
 /**
  * Supports proxy settings using system properties This proxy selector
@@ -87,9 +88,31 @@
 
     private static boolean hasSystemProxies = false;
 
+    // Android-removed: Nonfunctional init logic: "net" library does not exist on Android.
+    /*
+    static {
+        final String key = "java.net.useSystemProxies";
+        Boolean b = AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return NetProperties.getBoolean(key);
+                }});
+        if (b != null && b.booleanValue()) {
+            java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Void>() {
+                    public Void run() {
+                        System.loadLibrary("net");
+                        return null;
+                    }
+                });
+            hasSystemProxies = init();
+        }
+    }
+    */
+
     /**
      * How to deal with "non proxy hosts":
-     * since we do have to generate a RegexpPool we don't want to do that if
+     * since we do have to generate a pattern we don't want to do that if
      * it's not necessary. Therefore we do cache the result, on a per-protocol
      * basis, and change it only when the "source", i.e. the system property,
      * did change.
@@ -101,17 +124,19 @@
         static final String defStringVal = "localhost|127.*|[::1]|0.0.0.0|[::0]";
 
         String hostsSource;
-        RegexpPool hostsPool;
+        Pattern pattern;
         final String property;
         final String defaultVal;
         static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null, defStringVal);
         static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null, defStringVal);
+        static NonProxyInfo socksNonProxyInfo = new NonProxyInfo("socksNonProxyHosts", null, null, defStringVal);
+        // Android-changed: Different NonProxyInfo flags for https hosts vs. http.
         static NonProxyInfo httpsNonProxyInfo = new NonProxyInfo("https.nonProxyHosts", null, null, defStringVal);
 
-        NonProxyInfo(String p, String s, RegexpPool pool, String d) {
+        NonProxyInfo(String p, String s, Pattern pattern, String d) {
             property = p;
             hostsSource = s;
-            hostsPool = pool;
+            this.pattern = pattern;
             defaultVal = d;
         }
     }
@@ -166,11 +191,13 @@
         } else if ("https".equalsIgnoreCase(protocol)) {
             // HTTPS uses the same property as HTTP, for backward
             // compatibility
-            //
-            // Android-changed: Allow a different set of flags for https hosts.
+            // Android-changed: Different NonProxyInfo flags for https hosts vs. http.
+            // pinfo = NonProxyInfo.httpNonProxyInfo;
             pinfo = NonProxyInfo.httpsNonProxyInfo;
         } else if ("ftp".equalsIgnoreCase(protocol)) {
             pinfo = NonProxyInfo.ftpNonProxyInfo;
+        } else if ("socket".equalsIgnoreCase(protocol)) {
+            pinfo = NonProxyInfo.socksNonProxyInfo;
         }
 
         /**
@@ -214,7 +241,20 @@
                                  * settings (Gnome & Windows) if we were
                                  * instructed to.
                                  */
-                                // Android-changed, hasSystemProxies is always false
+                                // Android-removed: Dead code, hasSystemProxies is always false.
+                                /*
+                                if (hasSystemProxies) {
+                                    String sproto;
+                                    if (proto.equalsIgnoreCase("socket"))
+                                        sproto = "socks";
+                                    else
+                                        sproto = proto;
+                                    Proxy sproxy = getSystemProxy(sproto, urlhost);
+                                    if (sproxy != null) {
+                                        return sproxy;
+                                    }
+                                }
+                                */
                                 return Proxy.NO_PROXY;
                             }
                             // If a Proxy Host is defined for that protocol
@@ -227,7 +267,7 @@
                                             nphosts = nprop.defaultVal;
                                         } else {
                                             nprop.hostsSource = null;
-                                            nprop.hostsPool = null;
+                                            nprop.pattern = null;
                                         }
                                     } else if (nphosts.length() != 0) {
                                         // add the required default patterns
@@ -238,20 +278,11 @@
                                     }
                                     if (nphosts != null) {
                                         if (!nphosts.equals(nprop.hostsSource)) {
-                                            RegexpPool pool = new RegexpPool();
-                                            StringTokenizer st = new StringTokenizer(nphosts, "|", false);
-                                            try {
-                                                while (st.hasMoreTokens()) {
-                                                    pool.add(st.nextToken().toLowerCase(), Boolean.TRUE);
-                                                }
-                                            } catch (sun.misc.REException ex) {
-                                            }
-                                            nprop.hostsPool = pool;
+                                            nprop.pattern = toPattern(nphosts);
                                             nprop.hostsSource = nphosts;
                                         }
                                     }
-                                    if (nprop.hostsPool != null &&
-                                        nprop.hostsPool.match(urlhost) != null) {
+                                    if (shouldNotUseProxyFor(nprop.pattern, urlhost)) {
                                         return Proxy.NO_PROXY;
                                     }
                                 }
@@ -324,4 +355,55 @@
             return -1;
         }
     }
+
+    // Android-removed: Native logic not available/used on Android.
+    /*
+    private native static boolean init();
+    private synchronized native Proxy getSystemProxy(String protocol, String host);
+    */
+
+    /**
+     * @return {@code true} if given this pattern for non-proxy hosts and this
+     *         urlhost the proxy should NOT be used to access this urlhost
+     */
+    static boolean shouldNotUseProxyFor(Pattern pattern, String urlhost) {
+        if (pattern == null || urlhost.isEmpty())
+            return false;
+        boolean matches = pattern.matcher(urlhost).matches();
+        return matches;
+    }
+
+    /**
+     * @param mask non-null mask
+     * @return {@link java.util.regex.Pattern} corresponding to this mask
+     *         or {@code null} in case mask should not match anything
+     */
+    static Pattern toPattern(String mask) {
+        boolean disjunctionEmpty = true;
+        StringJoiner joiner = new StringJoiner("|");
+        for (String disjunct : mask.split("\\|")) {
+            if (disjunct.isEmpty())
+                continue;
+            disjunctionEmpty = false;
+            String regex = disjunctToRegex(disjunct.toLowerCase());
+            joiner.add(regex);
+        }
+        return disjunctionEmpty ? null : Pattern.compile(joiner.toString());
+    }
+
+    /**
+     * @param disjunct non-null mask disjunct
+     * @return java regex string corresponding to this mask
+     */
+    static String disjunctToRegex(String disjunct) {
+        String regex;
+        if (disjunct.startsWith("*")) {
+            regex = ".*" + quote(disjunct.substring(1));
+        } else if (disjunct.endsWith("*")) {
+            regex = quote(disjunct.substring(0, disjunct.length() - 1)) + ".*";
+        } else {
+            regex = quote(disjunct);
+        }
+        return regex;
+    }
 }
diff --git a/ojluni/src/main/java/sun/net/util/IPAddressUtil.java b/ojluni/src/main/java/sun/net/util/IPAddressUtil.java
index 7ca0f12..4a58e5f 100644
--- a/ojluni/src/main/java/sun/net/util/IPAddressUtil.java
+++ b/ojluni/src/main/java/sun/net/util/IPAddressUtil.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,89 +37,84 @@
      * @param src a String representing an IPv4 address in standard format
      * @return a byte array representing the IPv4 numeric address
      */
+    @SuppressWarnings("fallthrough")
     public static byte[] textToNumericFormatV4(String src)
     {
-        if (src.length() == 0) {
+        byte[] res = new byte[INADDR4SZ];
+
+        long tmpValue = 0;
+        int currByte = 0;
+        boolean newOctet = true;
+
+        int len = src.length();
+        if (len == 0 || len > 15) {
             return null;
         }
-
-        byte[] res = new byte[INADDR4SZ];
-        String[] s = src.split("\\.", -1);
-        long val;
-        try {
-            switch(s.length) {
-            // BEGIN Android-removed
-            /*
-            case 1:
-                // When only one part is given, the value is stored directly in
-                // the network address without any byte rearrangement.
-
-                val = Long.parseLong(s[0]);
-                if (val < 0 || val > 0xffffffffL)
+        /*
+         * When only one part is given, the value is stored directly in
+         * the network address without any byte rearrangement.
+         *
+         * When a two part address is supplied, the last part is
+         * interpreted as a 24-bit quantity and placed in the right
+         * most three bytes of the network address. This makes the
+         * two part address format convenient for specifying Class A
+         * network addresses as net.host.
+         *
+         * When a three part address is specified, the last part is
+         * interpreted as a 16-bit quantity and placed in the right
+         * most two bytes of the network address. This makes the
+         * three part address format convenient for specifying
+         * Class B net- work addresses as 128.net.host.
+         *
+         * When four parts are specified, each is interpreted as a
+         * byte of data and assigned, from left to right, to the
+         * four bytes of an IPv4 address.
+         *
+         * We determine and parse the leading parts, if any, as single
+         * byte values in one pass directly into the resulting byte[],
+         * then the remainder is treated as a 8-to-32-bit entity and
+         * translated into the remaining bytes in the array.
+         */
+        for (int i = 0; i < len; i++) {
+            char c = src.charAt(i);
+            if (c == '.') {
+                if (newOctet || tmpValue < 0 || tmpValue > 0xff || currByte == 3) {
                     return null;
-                res[0] = (byte) ((val >> 24) & 0xff);
-                res[1] = (byte) (((val & 0xffffff) >> 16) & 0xff);
-                res[2] = (byte) (((val & 0xffff) >> 8) & 0xff);
-                res[3] = (byte) (val & 0xff);
-                break;
-            case 2:
-                // When a two part address is supplied, the last part is
-                // interpreted as a 24-bit quantity and placed in the right
-                // most three bytes of the network address. This makes the
-                // two part address format convenient for specifying Class A
-                // network addresses as net.host.
-
-                val = Integer.parseInt(s[0]);
-                if (val < 0 || val > 0xff)
-                    return null;
-                res[0] = (byte) (val & 0xff);
-                val = Integer.parseInt(s[1]);
-                if (val < 0 || val > 0xffffff)
-                    return null;
-                res[1] = (byte) ((val >> 16) & 0xff);
-                res[2] = (byte) (((val & 0xffff) >> 8) &0xff);
-                res[3] = (byte) (val & 0xff);
-                break;
-            case 3:
-                //
-                // When a three part address is specified, the last part is
-                // interpreted as a 16-bit quantity and placed in the right
-                // most two bytes of the network address. This makes the
-                // three part address format convenient for specifying
-                // Class B net- work addresses as 128.net.host.
-                for (int i = 0; i < 2; i++) {
-                    val = Integer.parseInt(s[i]);
-                    if (val < 0 || val > 0xff)
-                        return null;
-                    res[i] = (byte) (val & 0xff);
                 }
-                val = Integer.parseInt(s[2]);
-                if (val < 0 || val > 0xffff)
+                res[currByte++] = (byte) (tmpValue & 0xff);
+                tmpValue = 0;
+                newOctet = true;
+            } else {
+                int digit = Character.digit(c, 10);
+                if (digit < 0) {
                     return null;
-                res[2] = (byte) ((val >> 8) & 0xff);
-                res[3] = (byte) (val & 0xff);
-                break;
-            */
-            // END Android-removed
-            case 4:
-                /*
-                 * When four parts are specified, each is interpreted as a
-                 * byte of data and assigned, from left to right, to the
-                 * four bytes of an IPv4 address.
-                 */
-                for (int i = 0; i < 4; i++) {
-                    val = Integer.parseInt(s[i]);
-                    if (val < 0 || val > 0xff)
-                        return null;
-                    res[i] = (byte) (val & 0xff);
                 }
-                break;
-            default:
-                return null;
+                tmpValue *= 10;
+                tmpValue += digit;
+                newOctet = false;
             }
-        } catch(NumberFormatException e) {
+        }
+        if (newOctet || tmpValue < 0 || tmpValue >= (1L << ((4 - currByte) * 8))) {
             return null;
         }
+        switch (currByte) {
+            // BEGIN Android-changed: Require all four parts to be given for an IPv4 address.
+            /*
+            case 0:
+                res[0] = (byte) ((tmpValue >> 24) & 0xff);
+            case 1:
+                res[1] = (byte) ((tmpValue >> 16) & 0xff);
+            case 2:
+                res[2] = (byte) ((tmpValue >>  8) & 0xff);
+            */
+            case 0:
+            case 1:
+            case 2:
+                return null;
+            // END Android-changed: Require all four parts to be given for an IPv4 address.
+            case 3:
+                res[3] = (byte) ((tmpValue >>  0) & 0xff);
+        }
         return res;
     }
 
diff --git a/ojluni/src/main/java/sun/net/util/URLUtil.java b/ojluni/src/main/java/sun/net/util/URLUtil.java
index 08c1e43..c25defb 100644
--- a/ojluni/src/main/java/sun/net/util/URLUtil.java
+++ b/ojluni/src/main/java/sun/net/util/URLUtil.java
@@ -76,5 +76,29 @@
 
         return strForm.toString();
     }
+
+    // Android-removed: Android doesn't support SecurityManager, so Permissions logic is dead code.
+    /*
+    public static Permission getConnectPermission(URL url) throws IOException {
+        String urlStringLowerCase = url.toString().toLowerCase();
+        if (urlStringLowerCase.startsWith("http:") || urlStringLowerCase.startsWith("https:")) {
+            return getURLConnectPermission(url);
+        } else if (urlStringLowerCase.startsWith("jar:http:") || urlStringLowerCase.startsWith("jar:https:")) {
+            String urlString = url.toString();
+            int bangPos = urlString.indexOf("!/");
+            urlString = urlString.substring(4, bangPos > -1 ? bangPos : urlString.length());
+            URL u = new URL(urlString);
+            return getURLConnectPermission(u);
+            // If protocol is HTTP or HTTPS than use URLPermission object
+        } else {
+            return url.openConnection().getPermission();
+        }
+    }
+
+    private static Permission getURLConnectPermission(URL url) {
+        String urlString = url.getProtocol() + "://" + url.getAuthority() + url.getPath();
+        return new URLPermission(urlString);
+    }
+    */
 }
 
diff --git a/ojluni/src/main/java/sun/net/www/MessageHeader.java b/ojluni/src/main/java/sun/net/www/MessageHeader.java
index 0237a85..34b6307 100644
--- a/ojluni/src/main/java/sun/net/www/MessageHeader.java
+++ b/ojluni/src/main/java/sun/net/www/MessageHeader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,13 +31,7 @@
 
 import java.io.*;
 import java.util.Collections;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Set;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
+import java.util.*;
 
 /** An RFC 844 or MIME message header.  Includes methods
     for parsing headers from incoming streams, fetching
@@ -61,6 +55,17 @@
     }
 
     /**
+     * Returns list of header names in a comma separated list
+     */
+    public synchronized String getHeaderNamesInList() {
+        StringJoiner joiner = new StringJoiner(",");
+        for (int i=0; i<nkeys; i++) {
+            joiner.add(keys[i]);
+        }
+        return joiner.toString();
+    }
+
+    /**
      * Reset a message header (all key/values removed)
      */
     public synchronized void reset() {
@@ -148,7 +153,7 @@
         for (int i=0; i<nkeys; i++) {
             if (k.equalsIgnoreCase(keys[i])
                     && values[i] != null && values[i].length() > 5
-                    && values[i].regionMatches(true, 0, "NTLM ", 0, 5)) {
+                    && values[i].substring(0, 5).equalsIgnoreCase("NTLM ")) {
                 found = true;
                 break;
             }
@@ -236,7 +241,8 @@
         return filterAndAddHeaders(excludeList, null);
     }
 
-    public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>>  include) {
+    public synchronized Map<String, List<String>> filterAndAddHeaders(
+            String[] excludeList, Map<String, List<String>>  include) {
         boolean skipIt = false;
         Map<String, List<String>> m = new HashMap<String, List<String>>();
         for (int i = nkeys; --i >= 0;) {
@@ -265,15 +271,13 @@
         }
 
         if (include != null) {
-            Iterator entries = include.entrySet().iterator();
-            while (entries.hasNext()) {
-                Map.Entry entry = (Map.Entry)entries.next();
-                List l = (List)m.get(entry.getKey());
+                for (Map.Entry<String,List<String>> entry: include.entrySet()) {
+                List<String> l = m.get(entry.getKey());
                 if (l == null) {
-                    l = new ArrayList();
-                    m.put((String)entry.getKey(), l);
+                    l = new ArrayList<String>();
+                    m.put(entry.getKey(), l);
                 }
-                l.add(entry.getValue());
+                l.addAll(entry.getValue());
             }
         }
 
@@ -437,6 +441,7 @@
     }
 
     /** Parse and merge a MIME header from an input stream. */
+    @SuppressWarnings("fallthrough")
     public void mergeHeader(InputStream is) throws java.io.IOException {
         if (is == null)
             return;
@@ -458,6 +463,7 @@
                         break;
                       case '\t':
                         c = ' ';
+                      /*fall through*/
                       case ' ':
                         inKey = false;
                         break;
diff --git a/ojluni/src/main/java/sun/net/www/MeteredStream.java b/ojluni/src/main/java/sun/net/www/MeteredStream.java
index 17c8b83..26fe85d 100644
--- a/ojluni/src/main/java/sun/net/www/MeteredStream.java
+++ b/ojluni/src/main/java/sun/net/www/MeteredStream.java
@@ -142,15 +142,17 @@
             return 0;
         }
 
-// Android-changed: Remove support for Android-removed class ChunkedInputSTream
-//        if (in instanceof ChunkedInputStream) {
-//            n = in.skip(n);
-//        }
-//        else {
+        // Android-removed: Removed support for Android-removed class ChunkedInputStream.
+        /*
+        if (in instanceof ChunkedInputStream) {
+            n = in.skip(n);
+        }
+        else {
+        */
             // just skip min(n, num_bytes_left)
             long min = (n > expected - count) ? expected - count: n;
             n = in.skip(min);
-//        }
+        // }
         justRead(n);
         return n;
     }
diff --git a/ojluni/src/main/java/sun/net/www/URLConnection.java b/ojluni/src/main/java/sun/net/www/URLConnection.java
index 2760acc..c495928 100644
--- a/ojluni/src/main/java/sun/net/www/URLConnection.java
+++ b/ojluni/src/main/java/sun/net/www/URLConnection.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,12 +26,7 @@
 package sun.net.www;
 
 import java.net.URL;
-import java.net.ContentHandler;
 import java.util.*;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.BufferedInputStream;
-import java.net.UnknownServiceException;
 
 /**
  * A class to represent an active connection to an object
@@ -99,7 +94,7 @@
     public Map<String,List<String>> getRequestProperties() {
         if (connected)
             throw new IllegalStateException("Already connected");
-        return Collections.EMPTY_MAP;
+        return Collections.emptyMap();
     }
 
     public String getHeaderField(String name) {
diff --git a/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java b/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java
index 24f2f3b..e9f3d78 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java
@@ -81,10 +81,12 @@
  */
 public class FtpURLConnection extends URLConnection {
 
-// Android-changed: Removed support for proxying FTP over HTTP since it
-// relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
-//    // In case we have to use proxies, we use HttpURLConnection
-//    HttpURLConnection http = null;
+    // Android-changed: Removed support for proxying FTP over HTTP.
+    // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+    /*
+    // In case we have to use proxies, we use HttpURLConnection
+    HttpURLConnection http = null;
+    */
     private Proxy instProxy;
 
     InputStream is = null;
@@ -163,6 +165,8 @@
      *
      * @param   url     The <code>URL</code> to retrieve or store.
      */
+    // Android-changed: Ctors can throw IOException for NetworkSecurityPolicy enforcement.
+    // public FtpURLConnection(URL url) {
     public FtpURLConnection(URL url) throws IOException {
         this(url, null);
     }
@@ -170,19 +174,22 @@
     /**
      * Same as FtpURLconnection(URL) with a per connection proxy specified
      */
+    // Android-changed: Ctors can throw IOException for NetworkSecurityPolicy enforcement.
+    // FtpURLConnection(URL url, Proxy p) {
     FtpURLConnection(URL url, Proxy p) throws IOException {
         super(url);
         instProxy = p;
         host = url.getHost();
         port = url.getPort();
         String userInfo = url.getUserInfo();
-
+        // BEGIN Android-added: Enforce NetworkSecurityPolicy.isClearTextTrafficPermitted().
         if (!NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()) {
             // Cleartext network traffic is not permitted -- refuse this connection.
             throw new IOException("Cleartext traffic not permitted: "
                     + url.getProtocol() + "://" + host
                     + ((url.getPort() >= 0) ? (":" + url.getPort()) : ""));
         }
+        // END Android-added: Enforce NetworkSecurityPolicy.isClearTextTrafficPermitted().
 
         if (userInfo != null) { // get the user and password
             int delimiter = userInfo.indexOf(':');
@@ -246,50 +253,56 @@
                         continue;
                     }
                     // OK, we have an http proxy
-                    // Android-changed: Removed support for proxying FTP over HTTP since it
-                    // relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+                    // BEGIN Android-changed: Removed support for proxying FTP over HTTP.
+                    // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+                    /*
+                    InetSocketAddress paddr = (InetSocketAddress) p.address();
+                    try {
+                        http = new HttpURLConnection(url, p);
+                        http.setDoInput(getDoInput());
+                        http.setDoOutput(getDoOutput());
+                        if (connectTimeout >= 0) {
+                            http.setConnectTimeout(connectTimeout);
+                        }
+                        if (readTimeout >= 0) {
+                            http.setReadTimeout(readTimeout);
+                        }
+                        http.connect();
+                        connected = true;
+                        return;
+                    } catch (IOException ioe) {
+                        sel.connectFailed(uri, paddr, ioe);
+                        http = null;
+                    }
+                    */
                     sel.connectFailed(uri, p.address(), new IOException("FTP connections over HTTP proxy not supported"));
                     continue;
-//                    InetSocketAddress paddr = (InetSocketAddress) p.address();
-//                    try {
-//                        http = new HttpURLConnection(url, p);
-//                        http.setDoInput(getDoInput());
-//                        http.setDoOutput(getDoOutput());
-//                        if (connectTimeout >= 0) {
-//                            http.setConnectTimeout(connectTimeout);
-//                        }
-//                        if (readTimeout >= 0) {
-//                            http.setReadTimeout(readTimeout);
-//                        }
-//                        http.connect();
-//                        connected = true;
-//                        return;
-//                    } catch (IOException ioe) {
-//                        sel.connectFailed(uri, paddr, ioe);
-//                        http = null;
-//                    }
+                    // END Android-changed: Removed support for proxying FTP over HTTP.
                 }
             }
         } else { // per connection proxy specified
             p = instProxy;
-// Android-changed: Removed support for proxying FTP over HTTP since it
-// relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
-// As specified in the documentation for URL.openConnection(Proxy), we
-// ignore the unsupported proxy and attempt a normal (direct) connection
-//            if (p.type() == Proxy.Type.HTTP) {
-//                http = new HttpURLConnection(url, instProxy);
-//                http.setDoInput(getDoInput());
-//                http.setDoOutput(getDoOutput());
-//                if (connectTimeout >= 0) {
-//                    http.setConnectTimeout(connectTimeout);
-//                }
-//                if (readTimeout >= 0) {
-//                    http.setReadTimeout(readTimeout);
-//                }
-//                http.connect();
-//                connected = true;
-//                return;
-//            }
+            // BEGIN Android-changed: Removed support for proxying FTP over HTTP.
+            // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+            // As specified in the documentation for URL.openConnection(Proxy), we
+            // ignore the unsupported proxy and attempt a normal (direct) connection
+            /*
+            if (p.type() == Proxy.Type.HTTP) {
+                http = new HttpURLConnection(url, instProxy);
+                http.setDoInput(getDoInput());
+                http.setDoOutput(getDoOutput());
+                if (connectTimeout >= 0) {
+                    http.setConnectTimeout(connectTimeout);
+                }
+                if (readTimeout >= 0) {
+                    http.setReadTimeout(readTimeout);
+                }
+                http.connect();
+                connected = true;
+                return;
+            }
+            */
+            // END Android-changed: Removed support for proxying FTP over HTTP.
         }
 
         if (user == null) {
@@ -319,7 +332,7 @@
             throw new IOException(fe);
         }
         try {
-            ftp.login(user, password.toCharArray());
+            ftp.login(user, password == null ? null : password.toCharArray());
         } catch (sun.net.ftp.FtpProtocolException e) {
             ftp.close();
             // Backward compatibility
@@ -410,11 +423,14 @@
         if (!connected) {
             connect();
         }
-        // Android-changed: Removed support for proxying FTP over HTTP since it
-        // relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
-//        if (http != null) {
-//            return http.getInputStream();
-//        }
+
+        // Android-changed: Removed support for proxying FTP over HTTP.
+        // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+        /*
+        if (http != null) {
+            return http.getInputStream();
+        }
+        */
 
         if (os != null) {
             throw new IOException("Already opened for output");
@@ -525,15 +541,18 @@
         if (!connected) {
             connect();
         }
-// Android-changed: Removed support for proxying FTP over HTTP since it
-// relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
-//        if (http != null) {
-//            OutputStream out = http.getOutputStream();
-//            // getInputStream() is neccessary to force a writeRequests()
-//            // on the http client.
-//            http.getInputStream();
-//            return out;
-//        }
+
+        // Android-changed: Removed support for proxying FTP over HTTP.
+        // It relies on the removed sun.net.www.protocol.http.HttpURLConnection API.
+        /*
+        if (http != null) {
+            OutputStream out = http.getOutputStream();
+            // getInputStream() is neccessary to force a writeRequests()
+            // on the http client.
+            http.getInputStream();
+            return out;
+        }
+        */
 
         if (is != null) {
             throw new IOException("Already opened for input");
diff --git a/ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java b/ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java
index 62686c6..8e9f8e3 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java
@@ -123,6 +123,7 @@
 
 
     @Override
+    @SuppressWarnings("deprecation")
     protected void parseURL(URL url, String spec,
                             int start, int limit) {
         String file = null;
diff --git a/ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java b/ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java
index ae86964..edd99ff 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java b/ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java
index 4c5dc87..d7c4424 100644
--- a/ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java
+++ b/ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -125,7 +125,9 @@
              * to get the jarFile, and set it as our permission.
              */
             if (getUseCaches()) {
+                boolean oldUseCaches = jarFileURLConnection.getUseCaches();
                 jarFileURLConnection = factory.getConnection(jarFile);
+                jarFileURLConnection.setUseCaches(oldUseCaches);
             }
 
             if ((entryName != null)) {
diff --git a/ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java b/ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java
index 762df01..3923675 100644
--- a/ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java
+++ b/ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java
@@ -361,9 +361,7 @@
         return dc;
     }
 
-    /*
-     * Android-added: for testing and internal use.
-     */
+    // Android-added: for testing and internal use.
     @Override
     public final FileDescriptor getFileDescriptor$() {
         return dc.fd;
diff --git a/ojluni/src/main/java/sun/nio/ch/IOUtil.java b/ojluni/src/main/java/sun/nio/ch/IOUtil.java
index 86dab9f..6988b86 100644
--- a/ojluni/src/main/java/sun/nio/ch/IOUtil.java
+++ b/ojluni/src/main/java/sun/nio/ch/IOUtil.java
@@ -345,7 +345,31 @@
 
     static native int iovMax();
 
+    // Android-removed: Code to load native libraries, doesn't make sense on Android.
+    /*
+    static native void initIDs();
+
+    /**
+     * Used to trigger loading of native libraries
+     *
+    public static void load() { }
+    */
+
     static {
+        // Android-removed: Code to load native libraries, doesn't make sense on Android.
+        /*
+        java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Void>() {
+                    public Void run() {
+                        System.loadLibrary("net");
+                        System.loadLibrary("nio");
+                        return null;
+                    }
+                });
+
+        initIDs();
+        */
+
         IOV_MAX = iovMax();
     }
 
diff --git a/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java b/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java
index aa6d834..a2aba2d 100644
--- a/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java
+++ b/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java
@@ -453,9 +453,7 @@
         return !sc.isOutputOpen();
     }
 
-    /*
-     * Android-added: for testing and internal use.
-     */
+    // Android-added: for testing and internal use.
     @Override
     public FileDescriptor getFileDescriptor$() {
         return sc.getFD();
diff --git a/ojluni/src/main/java/sun/reflect/CallerSensitive.java b/ojluni/src/main/java/sun/reflect/CallerSensitive.java
index 79fbdfc..0c78da0 100644
--- a/ojluni/src/main/java/sun/reflect/CallerSensitive.java
+++ b/ojluni/src/main/java/sun/reflect/CallerSensitive.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/sun/reflect/Reflection.java b/ojluni/src/main/java/sun/reflect/Reflection.java
index a3fa56d..bb82b43 100644
--- a/ojluni/src/main/java/sun/reflect/Reflection.java
+++ b/ojluni/src/main/java/sun/reflect/Reflection.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,8 +35,10 @@
 
 public class Reflection {
 
-    public static void ensureMemberAccess(Class currentClass,
-                                          Class memberClass,
+    // Android-removed: Dead code: Misc unused fields and methods.
+
+    public static void ensureMemberAccess(Class<?> currentClass,
+                                          Class<?> memberClass,
                                           Object target,
                                           int modifiers)
         throws IllegalAccessException
@@ -55,13 +57,13 @@
         }
     }
 
-    public static boolean verifyMemberAccess(Class currentClass,
+    public static boolean verifyMemberAccess(Class<?> currentClass,
                                              // Declaring class of field
                                              // or method
-                                             Class  memberClass,
+                                             Class<?> memberClass,
                                              // May be NULL in case of statics
-                                             Object target,
-                                             int    modifiers)
+                                             Object   target,
+                                             int      modifiers)
     {
         // Verify that currentClass can access a field, method, or
         // constructor of memberClass, where that member's access bits are
@@ -118,7 +120,7 @@
 
         if (Modifier.isProtected(modifiers)) {
             // Additional test for protected members: JLS 6.6.2
-            Class targetClass = (target == null ? memberClass : target.getClass());
+            Class<?> targetClass = (target == null ? memberClass : target.getClass());
             if (targetClass != currentClass) {
                 if (!gotIsSameClassPackage) {
                     isSameClassPackage = isSameClassPackage(currentClass, memberClass);
@@ -135,7 +137,7 @@
         return true;
     }
 
-    private static boolean isSameClassPackage(Class c1, Class c2) {
+    private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) {
         return isSameClassPackage(c1.getClassLoader(), c1.getName(),
                                   c2.getClassLoader(), c2.getName());
     }
@@ -190,8 +192,8 @@
         }
     }
 
-    static boolean isSubclassOf(Class queryClass,
-                                Class ofClass)
+    static boolean isSubclassOf(Class<?> queryClass,
+                                Class<?> ofClass)
     {
         while (queryClass != null) {
             if (queryClass == ofClass) {
@@ -201,4 +203,7 @@
         }
         return false;
     }
+
+    // Android-removed: Dead code: Misc unused methods.
+
 }
diff --git a/ojluni/src/main/java/sun/reflect/misc/ReflectUtil.java b/ojluni/src/main/java/sun/reflect/misc/ReflectUtil.java
index f9c2928..5896f15 100644
--- a/ojluni/src/main/java/sun/reflect/misc/ReflectUtil.java
+++ b/ojluni/src/main/java/sun/reflect/misc/ReflectUtil.java
@@ -33,20 +33,22 @@
     private ReflectUtil() {
     }
 
-    public static Class forName(String name)
+    public static Class<?> forName(String name)
         throws ClassNotFoundException {
         checkPackageAccess(name);
         return Class.forName(name);
     }
 
-    public static Object newInstance(Class cls)
+    public static Object newInstance(Class<?> cls)
         throws InstantiationException, IllegalAccessException {
         checkPackageAccess(cls);
         return cls.newInstance();
     }
 
-    private static boolean isSubclassOf(Class queryClass,
-                                Class ofClass)
+    // Android-removed: Dead code: Unused method ensureMemberAccess()
+
+    private static boolean isSubclassOf(Class<?> queryClass,
+                                        Class<?> ofClass)
     {
         while (queryClass != null) {
             if (queryClass == ofClass) {
@@ -57,6 +59,8 @@
         return false;
     }
 
+    // Android-removed: Dead code: Unused method conservativeCheckMemberAccess()
+
     /**
      * Checks package access on the given class.
      *
@@ -94,7 +98,7 @@
         }
     }
 
-    public static boolean isPackageAccessible(Class clazz) {
+    public static boolean isPackageAccessible(Class<?> clazz) {
         try {
             checkPackageAccess(clazz);
         } catch (SecurityException e) {
@@ -177,6 +181,13 @@
         }
     }
 
+    // Android-changed: Proxy classes are generated in the default package on Android.
+    /*
+    // Note that bytecode instrumentation tools may exclude 'sun.*'
+    // classes but not generated proxy classes and so keep it in com.sun.*
+    public static final String PROXY_PACKAGE = "com.sun.proxy";
+    */
+
     /**
      * Test if the given class is a proxy class that implements
      * non-public interface.  Such proxy class may be in a non-restricted
@@ -186,10 +197,14 @@
         String name = cls.getName();
         int i = name.lastIndexOf('.');
         String pkg = (i != -1) ? name.substring(0, i) : "";
-
-        // NOTE: Android creates proxies in the "default" package (and not com.sun.proxy), which
-        // makes this check imprecise. However, this function is only ever called if there's
-        // a security manager installed (which is the never case on android).
+        // Android-changed: Proxy classes are generated in the default package on Android.
+        // The use of the default package (as opposed to com.sun.proxy) makes this check
+        // imprecise. However, this function is only ever called if there's
+        // a security manager installed (which is the never case on Android).
+        // return Proxy.isProxyClass(cls) && !pkg.equals(PROXY_PACKAGE);
         return Proxy.isProxyClass(cls) && !pkg.isEmpty();
     }
+
+    // Android-removed: Dead code: unused method checkProxyMethod()
+    // Android-removed: Dead code: unused method isVMAnonymousClass()
 }
diff --git a/ojluni/src/main/java/sun/security/jca/JCAUtil.java b/ojluni/src/main/java/sun/security/jca/JCAUtil.java
index b7bae41..fde9be5 100644
--- a/ojluni/src/main/java/sun/security/jca/JCAUtil.java
+++ b/ojluni/src/main/java/sun/security/jca/JCAUtil.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,12 +41,6 @@
         // no instantiation
     }
 
-    // lock to use for synchronization
-    private static final Object LOCK = JCAUtil.class;
-
-    // cached SecureRandom instance
-    private static volatile SecureRandom secureRandom;
-
     // size of the temporary arrays we use. Should fit into the CPU's 1st
     // level cache and could be adjusted based on the platform
     private final static int ARRAY_SIZE = 4096;
@@ -60,26 +54,19 @@
         return Math.min(ARRAY_SIZE, totalSize);
     }
 
+    // cached SecureRandom instance
+    private static class CachedSecureRandomHolder {
+        public static SecureRandom instance = new SecureRandom();
+    }
+
     /**
-     * Get a SecureRandom instance. This method should me used by JDK
+     * Get a SecureRandom instance. This method should be used by JDK
      * internal code in favor of calling "new SecureRandom()". That needs to
      * iterate through the provider table to find the default SecureRandom
      * implementation, which is fairly inefficient.
      */
     public static SecureRandom getSecureRandom() {
-        // we use double checked locking to minimize synchronization
-        // works because we use a volatile reference
-        SecureRandom r = secureRandom;
-        if (r == null) {
-            synchronized (LOCK) {
-                r = secureRandom;
-                if (r == null) {
-                    r = new SecureRandom();
-                    secureRandom = r;
-                }
-            }
-        }
-        return r;
+        return CachedSecureRandomHolder.instance;
     }
 
 }
diff --git a/ojluni/src/main/java/sun/security/jca/ProviderConfig.java b/ojluni/src/main/java/sun/security/jca/ProviderConfig.java
index fc4ee76..2acf30d 100644
--- a/ojluni/src/main/java/sun/security/jca/ProviderConfig.java
+++ b/ojluni/src/main/java/sun/security/jca/ProviderConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -209,6 +209,7 @@
                     debug.println("Loading provider: " + ProviderConfig.this);
                 }
 
+// BEGIN Android-changed: Prefer the boot classloader to the system classloader.
                 try {
                     // First try with the boot classloader.
                     return initProvider(className, Object.class.getClassLoader());
@@ -269,6 +270,7 @@
             return null;
         }
     }
+// END Android-changed: Prefer the boot classloader to the system classloader.
 
     /**
      * Perform property expansion of the provider value.
diff --git a/ojluni/src/main/java/sun/security/jca/ProviderList.java b/ojluni/src/main/java/sun/security/jca/ProviderList.java
index d9b04c6..66c8262 100644
--- a/ojluni/src/main/java/sun/security/jca/ProviderList.java
+++ b/ojluni/src/main/java/sun/security/jca/ProviderList.java
@@ -69,13 +69,7 @@
     // used to avoid explicit null checks in various places
     private static final Provider EMPTY_PROVIDER =
         new Provider("##Empty##", 1.0d, "initialization in progress") {
-            // BEGIN Android-added
-            // TODO(33172161): the computation of the default in Android yields
-            // -2591074641286775682L . Check why there's a difference and possibly change number
-            // accordingly.
-            // END Android-added
             private static final long serialVersionUID = 1151354171352296389L;
-            // END Android-changed
             // override getService() to return null slightly faster
             public Service getService(String type, String algorithm) {
                 return null;
diff --git a/ojluni/src/main/java/sun/security/jca/Providers.java b/ojluni/src/main/java/sun/security/jca/Providers.java
index ddcf505..e39543a 100644
--- a/ojluni/src/main/java/sun/security/jca/Providers.java
+++ b/ojluni/src/main/java/sun/security/jca/Providers.java
@@ -54,6 +54,7 @@
         providerList = ProviderList.EMPTY;
         providerList = ProviderList.fromSecurityProperties();
 
+        // BEGIN Android-added: Initialize all providers and assert that this succeeds.
         // removeInvalid is specified to try initializing all configured providers
         // and removing those that aren't instantiable. This has the side effect
         // of eagerly initializing all providers.
@@ -62,6 +63,7 @@
         if (numConfiguredProviders != providerList.size()) {
             throw new AssertionError("Unable to configure default providers");
         }
+        // END Android-added: Initialize all providers and assert that this succeeds.
     }
 
     private Providers() {
@@ -91,7 +93,7 @@
     // Hardcoded classnames of providers to use for JAR verification.
     // MUST NOT be on the bootclasspath and not in signed JAR files.
     private static final String[] jarVerificationProviders = {
-        // BEGIN Android-changed
+        // BEGIN Android-changed: Use Conscrypt and BC, not the sun.security providers.
         /*
         "sun.security.provider.Sun",
         "sun.security.rsa.SunRsaSign",
@@ -102,7 +104,7 @@
         "com.android.org.conscrypt.OpenSSLProvider",
         "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider",
         "com.android.org.conscrypt.JSSEProvider",
-        // END Android-changed
+        // END Android-changed: Use Conscrypt and BC, not the sun.security providers.
         BACKUP_PROVIDER_CLASSNAME,
     };
 
diff --git a/ojluni/src/main/java/sun/security/pkcs/PKCS7.java b/ojluni/src/main/java/sun/security/pkcs/PKCS7.java
index 49d898a..f28bea7 100644
--- a/ojluni/src/main/java/sun/security/pkcs/PKCS7.java
+++ b/ojluni/src/main/java/sun/security/pkcs/PKCS7.java
@@ -1026,7 +1026,8 @@
             byte[] content,
             String signatureAlgorithm,
             URI tsaURI,
-            String tSAPolicyID)
+            String tSAPolicyID,
+            String tSADigestAlg)
             throws CertificateException, IOException, NoSuchAlgorithmException
     {
 
@@ -1035,7 +1036,8 @@
         if (tsaURI != null) {
             // Timestamp the signature
             HttpTimestamper tsa = new HttpTimestamper(tsaURI);
-            byte[] tsToken = generateTimestampToken(tsa, tSAPolicyID, signature);
+            byte[] tsToken = generateTimestampToken(
+                    tsa, tSAPolicyID, tSADigestAlg, signature);
 
             // Insert the timestamp token into the PKCS #7 signer info element
             // (as an unsigned attribute)
@@ -1093,6 +1095,7 @@
      *
     private static byte[] generateTimestampToken(Timestamper tsa,
             String tSAPolicyID,
+            String tSADigestAlg,
             byte[] toBeTimestamped)
             throws IOException, CertificateException
     {
@@ -1100,11 +1103,10 @@
         MessageDigest messageDigest = null;
         TSRequest tsQuery = null;
         try {
-            // SHA-1 is always used.
-            messageDigest = MessageDigest.getInstance("SHA-1");
+            messageDigest = MessageDigest.getInstance(tSADigestAlg);
             tsQuery = new TSRequest(tSAPolicyID, toBeTimestamped, messageDigest);
         } catch (NoSuchAlgorithmException e) {
-            // ignore
+            throw new IllegalArgumentException(e);
         }
 
         // Generate a nonce
@@ -1132,9 +1134,13 @@
         PKCS7 tsToken = tsReply.getToken();
 
         TimestampToken tst = tsReply.getTimestampToken();
-        if (!tst.getHashAlgorithm().getName().equals("SHA-1")) {
-            throw new IOException("Digest algorithm not SHA-1 in "
-                    + "timestamp token");
+        try {
+            if (!tst.getHashAlgorithm().equals(AlgorithmId.get(tSADigestAlg))) {
+                throw new IOException("Digest algorithm not " + tSADigestAlg + " in "
+                                      + "timestamp token");
+            }
+        } catch (NoSuchAlgorithmException nase) {
+            throw new IllegalArgumentException();   // should have been caught before
         }
         if (!MessageDigest.isEqual(tst.getHashedMessage(),
                 tsQuery.getHashedMessage())) {
@@ -1172,5 +1178,6 @@
         }
         return tsReply.getEncodedToken();
     }
-    END Android-removed */
+    */
+    // END Android-removed: unused in Android
 }
diff --git a/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java b/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java
index e2f8e28..ef65da9 100644
--- a/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java
+++ b/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java
@@ -60,6 +60,7 @@
 import sun.security.util.DerOutputStream;
 import sun.security.util.DerValue;
 import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.util.KeyUtil;
 import sun.security.util.ObjectIdentifier;
 import sun.security.x509.AlgorithmId;
 import sun.security.x509.X500Name;
@@ -424,7 +425,9 @@
             // check if the public key is restricted
             if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
                 throw new SignatureException("Public key check failed. " +
-                        "Disabled algorithm used: " + key.getAlgorithm());
+                        "Disabled key used: " +
+                        KeyUtil.getKeySize(key) + " bit " +
+                        key.getAlgorithm());
             }
 
             if (cert.hasUnsupportedCriticalExtension()) {
@@ -530,6 +533,23 @@
         return unauthenticatedAttributes;
     }
 
+    /**
+     * Returns the timestamp PKCS7 data unverified.
+     * @return a PKCS7 object
+     */
+    public PKCS7 getTsToken() throws IOException {
+        if (unauthenticatedAttributes == null) {
+            return null;
+        }
+        PKCS9Attribute tsTokenAttr =
+                unauthenticatedAttributes.getAttribute(
+                        PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
+        if (tsTokenAttr == null) {
+            return null;
+        }
+        return new PKCS7((byte[])tsTokenAttr.getValue());
+    }
+
     /*
      * Extracts a timestamp from a PKCS7 SignerInfo.
      *
@@ -558,19 +578,12 @@
         if (timestamp != null || !hasTimestamp)
             return timestamp;
 
-        if (unauthenticatedAttributes == null) {
-            hasTimestamp = false;
-            return null;
-        }
-        PKCS9Attribute tsTokenAttr =
-            unauthenticatedAttributes.getAttribute(
-                PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
-        if (tsTokenAttr == null) {
+        PKCS7 tsToken = getTsToken();
+        if (tsToken == null) {
             hasTimestamp = false;
             return null;
         }
 
-        PKCS7 tsToken = new PKCS7((byte[])tsTokenAttr.getValue());
         // Extract the content (an encoded timestamp token info)
         byte[] encTsTokenInfo = tsToken.getContentInfo().getData();
         // Extract the signer (the Timestamping Authority)
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java b/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java
index 4e0c3b6..d2d9e36 100644
--- a/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java
@@ -94,9 +94,6 @@
             X509Certificate firstCert = certList.get(0);
             // check trusted certificate's subject
             selector.setSubject(firstCert.getIssuerX500Principal());
-            // check the validity period
-            selector.setValidityPeriod(firstCert.getNotBefore(),
-                                       firstCert.getNotAfter());
             /*
              * Facilitate certification path construction with authority
              * key identifier and subject key identifier.
diff --git a/ojluni/src/main/java/sun/security/util/Debug.java b/ojluni/src/main/java/sun/security/util/Debug.java
index 6ddb08d..ff5a879 100644
--- a/ojluni/src/main/java/sun/security/util/Debug.java
+++ b/ojluni/src/main/java/sun/security/util/Debug.java
@@ -26,9 +26,9 @@
 package sun.security.util;
 
 import java.math.BigInteger;
-import java.util.Locale;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.Locale;
 
 /**
  * A utility class for debuging.
@@ -37,15 +37,39 @@
  */
 public class Debug {
 
-    private static final String args = null;
+    private String prefix;
 
-    private final String prefix;
+    private static String args;
 
-    private Debug(String prefix) {
-        this.prefix = prefix;
+    // BEGIN Android-changed: Debug is stubbed and disabled on Android.
+    // Removing the static initializer removes the only pathway to set args, which
+    // in turn means that isOn() always returns false and so no code in this
+    // class does anything.
+    /*
+    static {
+        args = java.security.AccessController.doPrivileged
+                (new sun.security.action.GetPropertyAction
+                ("java.security.debug"));
+
+        String args2 = java.security.AccessController.doPrivileged
+                (new sun.security.action.GetPropertyAction
+                ("java.security.auth.debug"));
+
+        if (args == null) {
+            args = args2;
+        } else {
+            if (args2 != null)
+               args = args + "," + args2;
+        }
+
+        if (args != null) {
+            args = marshal(args);
+            if (args.equals("help")) {
+                Help();
+            }
+        }
     }
 
-    /*
         From public static void Help() : Serves as a documentation of the
         values that "args" accepts.
 
@@ -99,6 +123,7 @@
         System.err.println("Note: Separate multiple options with a comma");
         System.exit(0);
     */
+    // END Android-changed: Debug is stubbed and disabled on Android.
 
     /**
      * Get a Debug object corresponding to whether or not the given
@@ -117,7 +142,8 @@
     public static Debug getInstance(String option, String prefix)
     {
         if (isOn(option)) {
-            Debug d = new Debug(prefix);
+            Debug d = new Debug();
+            d.prefix = prefix;
             return d;
         } else {
             return null;
@@ -159,6 +185,16 @@
         System.err.println(prefix + ":");
     }
 
+    // Android-removed: Nothing uses this code and it serves no purpose.
+    /**
+     * print a message to stderr that is prefixed with the prefix.
+     *
+
+    public static void println(String prefix, String message)
+    {
+        System.err.println(prefix + ": "+message);
+    }
+     */
 
     /**
      * return a hexadecimal printed representation of the specified
diff --git a/ojluni/src/main/java/sun/security/util/DerInputStream.java b/ojluni/src/main/java/sun/security/util/DerInputStream.java
index b182d4e..6608676 100644
--- a/ojluni/src/main/java/sun/security/util/DerInputStream.java
+++ b/ojluni/src/main/java/sun/security/util/DerInputStream.java
@@ -325,6 +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
     public DerValue[] getSequence(int startLen,
             boolean originalEncodedFormRetained) throws IOException {
         tag = (byte)buffer.read();
@@ -347,6 +348,7 @@
         return getSequence(
                 startLen,
                 false); // no need to retain original encoded form
+        // END Android-changed: Original encoded form needed for APKs parsing/validation
     }
 
     /**
@@ -379,6 +381,7 @@
      */
     public DerValue[] getSet(int startLen, boolean implicit)
         throws IOException {
+        // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation
         return getSet(
             startLen,
             implicit,
@@ -395,6 +398,7 @@
             }
         }
         return (readVector(startLen, originalEncodedFormRetained));
+        // END Android-changed: Original encoded form needed for APKs parsing/validation
     }
 
     /*
@@ -403,6 +407,7 @@
      * this same helper routine.
      */
     protected DerValue[] readVector(int startLen) throws IOException {
+        // BEGIN Android-changed: Original encoded form needed for APKs parsing/validation
         return readVector(
             startLen,
             false); // no need to retain original encoded form
@@ -415,6 +420,7 @@
      */
     protected DerValue[] readVector(int startLen,
             boolean originalEncodedFormRetained) throws IOException {
+        // END Android-changed: Original encoded form needed for APKs parsing/validation
         DerInputStream  newstr;
 
         byte lenByte = (byte)buffer.read();
@@ -459,6 +465,7 @@
         DerValue value;
 
         do {
+            // 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 21116dc..3045995 100644
--- a/ojluni/src/main/java/sun/security/util/DerValue.java
+++ b/ojluni/src/main/java/sun/security/util/DerValue.java
@@ -72,11 +72,13 @@
 
     private int                 length;
 
+    // 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
 
     /*
      * The type starts at the first byte of the encoding, and
@@ -249,6 +251,7 @@
     /*
      * package private
      */
+    // 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
@@ -294,6 +297,7 @@
             int consumed = in.getPos() - startPosInInput;
             originalEncodedForm = in.getSlice(startPosInInput, consumed);
         }
+    // END Android-changed: Original encoded form needed for APKs parsing/validation
     }
 
     /**
@@ -834,6 +838,7 @@
         }
     }
 
+    // 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.
@@ -842,6 +847,7 @@
         return (originalEncodedForm != null)
                 ? originalEncodedForm.clone() : null;
     }
+    // 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/util/DisabledAlgorithmConstraints.java b/ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java
index aecb341..a46b318 100644
--- a/ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java
+++ b/ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -95,6 +95,7 @@
     @Override
     final public boolean permits(Set<CryptoPrimitive> primitives,
             String algorithm, AlgorithmParameters parameters) {
+
         if (primitives == null || primitives.isEmpty()) {
             throw new IllegalArgumentException(
                         "No cryptographic primitive specified");
@@ -297,6 +298,7 @@
                         c = new jdkCAConstraint(algorithm);
                         jdkCALimit = true;
                     }
+
                     // Link multiple conditions for a single constraint
                     // into a linked list.
                     if (lastConstraint == null) {
diff --git a/ojluni/src/main/java/sun/security/util/KeyUtil.java b/ojluni/src/main/java/sun/security/util/KeyUtil.java
index e3efcff..c12a4ce 100644
--- a/ojluni/src/main/java/sun/security/util/KeyUtil.java
+++ b/ojluni/src/main/java/sun/security/util/KeyUtil.java
@@ -1,6 +1,6 @@
 /*
  * Copyright 2016 The Android Open Source Project
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012,2016 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -91,18 +91,8 @@
             // END Android-changed
         } else if (key instanceof DSAKey) {
             DSAKey pubk = (DSAKey)key;
-            // BEGIN Android-changed
-            // Was: size = pubk.getParams().getP().bitLength();
-            DSAParams params = pubk.getParams();
-            // According to RFC 3279 section 2.3.2, DSA keys are allowed
-            // to inherit parameters in an X.509 certificate issuer's
-            // key parameters, so the parameters may be null. The parent
-            // key will be rejected if its parameters don't pass, so this
-            // is okay.
-            if (params != null) {
-                size = params.getP().bitLength();
-            }
-            // END Android-changed
+            DSAParams params = pubk.getParams();    // params can be null
+            size = (params != null) ? params.getP().bitLength() : -1;
         } else if (key instanceof DHKey) {
             DHKey pubk = (DHKey)key;
             size = pubk.getParams().getP().bitLength();
@@ -163,8 +153,6 @@
 
     /**
      * Returns whether the specified provider is Oracle provider or not.
-     * <P>
-     * Note that this method is only apply to SunJCE and SunPKCS11 at present.
      *
      * @param  providerName
      *         the provider name
@@ -172,8 +160,11 @@
      *         {@code providerName} is Oracle provider
      *
     public static final boolean isOracleJCEProvider(String providerName) {
-        return providerName != null && (providerName.equals("SunJCE") ||
-                                        providerName.startsWith("SunPKCS11"));
+        return providerName != null &&
+                (providerName.equals("SunJCE") ||
+                    providerName.equals("SunMSCAPI") ||
+                    providerName.equals("OracleUcrypto") ||
+                    providerName.startsWith("SunPKCS11"));
     }
 
     /**
@@ -218,7 +209,7 @@
             byte[] encoded, boolean isFailOver) {
 
         if (random == null) {
-            random = new SecureRandom();
+            random = JCAUtil.getSecureRandom();
         }
         byte[] replacer = new byte[48];
         random.nextBytes(replacer);
@@ -322,5 +313,5 @@
     }
     */
     // END Android-removed
-}
 
+}
diff --git a/ojluni/src/main/java/sun/security/util/ObjectIdentifier.java b/ojluni/src/main/java/sun/security/util/ObjectIdentifier.java
index 38d171a..58f26c3 100644
--- a/ojluni/src/main/java/sun/security/util/ObjectIdentifier.java
+++ b/ojluni/src/main/java/sun/security/util/ObjectIdentifier.java
@@ -255,7 +255,13 @@
                 + " (tag = " +  type_id + ")"
                 );
 
-        encoding = new byte[in.getLength()];
+        int len = in.getLength();
+        if (len > in.available()) {
+            throw new IOException("ObjectIdentifier() -- length exceeds" +
+                    "data available.  Length: " + len + ", Available: " +
+                    in.available());
+        }
+        encoding = new byte[len];
         in.getBytes(encoding);
         check(encoding);
     }
@@ -354,6 +360,7 @@
      * @return components in an int array, if all the components are less than
      *         Integer.MAX_VALUE. Otherwise, null.
      */
+    // Android-changed: s/private/public: Needed to keep sort order of RDN from prev impl
     public int[] toIntArray() {
         int length = encoding.length;
         int[] result = new int[20];
diff --git a/ojluni/src/main/java/sun/security/x509/AVA.java b/ojluni/src/main/java/sun/security/x509/AVA.java
index ff9c62a..a047500 100644
--- a/ojluni/src/main/java/sun/security/x509/AVA.java
+++ b/ojluni/src/main/java/sun/security/x509/AVA.java
@@ -150,9 +150,6 @@
 
     /**
      * Parse an AVA string formatted according to format.
-     *
-     * XXX format RFC1779 should only allow RFC1779 syntax but is
-     * actually DEFAULT with RFC1779 keywords.
      */
     AVA(Reader in, int format) throws IOException {
         this(in, format, Collections.<String, String>emptyMap());
@@ -272,7 +269,7 @@
                 break;
             }
 
-            // Android-changed: Skip trailing whitespace.
+            // BEGIN Android-added: AVA: Support DerValue hex strings that contain ' ' or '\n'
             if (c == ' ' || c == '\n') {
                 do {
                     if (c != ' ' && c != '\n') {
@@ -282,7 +279,7 @@
                 } while (!isTerminator(c, format));
                 break;
             }
-
+            // END Android-added: AVA: Support DerValue hex strings that contain ' ' or '\n'
             int cVal = hexDigits.indexOf(Character.toUpperCase((char)c));
 
             if (cVal == -1) {
@@ -384,11 +381,17 @@
                 PRESERVE_OLD_DC_ENCODING == false)) {
             // EmailAddress and DomainComponent must be IA5String
             return new DerValue(DerValue.tag_IA5String,
+            // Android-changed: Do not trim() DerValue strings.
+            //                            temp.toString().trim());
                                         temp.toString());
         } else if (isPrintableString) {
+            // Android-changed: Do not trim() DerValue strings.
+            //return new DerValue(temp.toString().trim());
             return new DerValue(temp.toString());
         } else {
             return new DerValue(DerValue.tag_UTF8String,
+            // Android-changed: Do not trim() DerValue strings.
+            //                            temp.toString().trim());
                                         temp.toString());
         }
     }
@@ -900,6 +903,8 @@
          * the dotted-decimal form.
          */
         if ((typeAndValue.charAt(0) >= '0' && typeAndValue.charAt(0) <= '9') ||
+            // Android-changed: AVA: Support DerValue hex strings that contain ' ' or '\n'
+            //!isDerString(value, true))
             (!isDerString(value, true) && value.tag != DerValue.tag_T61String))
         {
             byte[] data = null;
diff --git a/ojluni/src/main/java/sun/security/x509/AlgorithmId.java b/ojluni/src/main/java/sun/security/x509/AlgorithmId.java
index 378ca2f..260d4aa 100644
--- a/ojluni/src/main/java/sun/security/x509/AlgorithmId.java
+++ b/ojluni/src/main/java/sun/security/x509/AlgorithmId.java
@@ -121,18 +121,14 @@
         try {
             algParams = AlgorithmParameters.getInstance(algidString);
         } catch (NoSuchAlgorithmException e) {
-            // BEGIN Android-changed
-            // It was searching for the EC parameters in an internal provider in the deleted package
-            // sun.security.ec before setting them to null. Since EC is in the OpenSSL provider,
-            // there's no need for such fallback. Setting it to null directly.
             /*
              * This algorithm parameter type is not supported, so we cannot
              * parse the parameters.
              */
             algParams = null;
             return;
-            // END Android-changed
         }
+
         // Decode (parse) the parameters
         algParams.init(params.toByteArray());
     }
@@ -246,11 +242,13 @@
             }
         }
 
+        // BEGIN Android-added: Update algorithm mapping tables for names when OID is used
         // Try to update the name <-> OID mapping table.
         synchronized (oidTable) {
             reinitializeMappingTableLocked();
             algName = nameTable.get(algid);
         }
+        // END Android-added: Update algorithm mapping tables for names when OID is used
 
         return (algName == null) ? algid.toString() : algName;
     }
@@ -566,6 +564,7 @@
 
         // See if any of the installed providers supply a mapping from
         // the given algorithm name to an OID string
+        // BEGIN Android-changed: Update algorithm mapping tables for names when OID is used
         synchronized (oidTable) {
             reinitializeMappingTableLocked();
             return oidTable.get(name.toUpperCase(Locale.ENGLISH));
@@ -644,17 +643,20 @@
 
             initOidTableVersion = currentVersion;
         }
+    // END Android-changed: Update algorithm mapping tables for names when OID is used
     }
 
     private static ObjectIdentifier oid(int ... values) {
         return ObjectIdentifier.newInternal(values);
     }
 
+    // BEGIN Android-changed: Parsing mapping as OID even if "OID." prefix isn't specified
     private static int initOidTableVersion = -1;
     private static final Map<String,ObjectIdentifier> oidTable =
         new HashMap<String,ObjectIdentifier>(1);
     private static final Map<ObjectIdentifier,String> nameTable =
         new HashMap<ObjectIdentifier,String>();
+    // END Android-changed: Parsing mapping as OID even if "OID." prefix isn't specified
 
     /*****************************************************************/
 
@@ -939,6 +941,8 @@
      */
         sha1WithDSA_oid = ObjectIdentifier.newInternal(dsaWithSHA1_PKIX_data);
 
+        // Android-removed: Parsing mapping as OID even if "OID." prefix isn't specified
+        //nameTable = new HashMap<ObjectIdentifier,String>();
         nameTable.put(MD5_oid, "MD5");
         nameTable.put(MD2_oid, "MD2");
         nameTable.put(SHA_oid, "SHA-1");
diff --git a/ojluni/src/main/java/sun/security/x509/CRLDistributionPointsExtension.java b/ojluni/src/main/java/sun/security/x509/CRLDistributionPointsExtension.java
index c381430..9062a53 100644
--- a/ojluni/src/main/java/sun/security/x509/CRLDistributionPointsExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/CRLDistributionPointsExtension.java
@@ -29,6 +29,7 @@
 import java.io.OutputStream;
 
 import java.util.*;
+import java.util.Collections;
 
 import sun.security.util.DerOutputStream;
 import sun.security.util.DerValue;
@@ -255,11 +256,12 @@
      */
     public void delete(String name) throws IOException {
         if (name.equalsIgnoreCase(POINTS)) {
-            distributionPoints = new ArrayList<DistributionPoint>();
+            distributionPoints =
+                    Collections.<DistributionPoint>emptyList();
         } else {
             throw new IOException("Attribute name [" + name +
-                                "] not recognized by " +
-                                "CertAttrSet:" + extensionName + ".");
+                                  "] not recognized by " +
+                                  "CertAttrSet:" + extensionName + '.');
         }
         encodeThis();
     }
diff --git a/ojluni/src/main/java/sun/security/x509/CRLNumberExtension.java b/ojluni/src/main/java/sun/security/x509/CRLNumberExtension.java
index 9649df6..3abeb01 100644
--- a/ojluni/src/main/java/sun/security/x509/CRLNumberExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/CRLNumberExtension.java
@@ -157,11 +157,10 @@
      */
     public BigInteger get(String name) throws IOException {
         if (name.equalsIgnoreCase(NUMBER)) {
-            if (crlNumber == null) return null;
-            else return crlNumber;
+            return crlNumber;
         } else {
-          throw new IOException("Attribute name not recognized by"
-                                + " CertAttrSet:" + extensionName + ".");
+            throw new IOException("Attribute name not recognized by" +
+                                  " CertAttrSet:" + extensionName + '.');
         }
     }
 
diff --git a/ojluni/src/main/java/sun/security/x509/DNSName.java b/ojluni/src/main/java/sun/security/x509/DNSName.java
index 2a35b86..0946dd1b 100644
--- a/ojluni/src/main/java/sun/security/x509/DNSName.java
+++ b/ojluni/src/main/java/sun/security/x509/DNSName.java
@@ -232,15 +232,15 @@
      * @throws UnsupportedOperationException if not supported for this name type
      */
     public int subtreeDepth() throws UnsupportedOperationException {
-        String subtree=name;
-        int i=1;
+        // subtree depth is always at least 1
+        int sum = 1;
 
-        /* count dots */
-        for (; subtree.lastIndexOf('.') >= 0; i++) {
-            subtree=subtree.substring(0,subtree.lastIndexOf('.'));
+        // count dots
+        for (int i = name.indexOf('.'); i >= 0; i = name.indexOf('.', i + 1)) {
+            ++sum;
         }
 
-        return i;
+        return sum;
     }
 
 }
diff --git a/ojluni/src/main/java/sun/security/x509/EDIPartyName.java b/ojluni/src/main/java/sun/security/x509/EDIPartyName.java
index feaf30b..513e337 100644
--- a/ojluni/src/main/java/sun/security/x509/EDIPartyName.java
+++ b/ojluni/src/main/java/sun/security/x509/EDIPartyName.java
@@ -197,7 +197,7 @@
      */
     public int hashCode() {
         if (myhash == -1) {
-            myhash = 37 + party.hashCode();
+            myhash = 37 + (party == null ? 1 : party.hashCode());
             if (assigner != null) {
                 myhash = 37 * myhash + assigner.hashCode();
             }
diff --git a/ojluni/src/main/java/sun/security/x509/GeneralSubtrees.java b/ojluni/src/main/java/sun/security/x509/GeneralSubtrees.java
index 9c5e621..e5c9e73 100644
--- a/ojluni/src/main/java/sun/security/x509/GeneralSubtrees.java
+++ b/ojluni/src/main/java/sun/security/x509/GeneralSubtrees.java
@@ -191,7 +191,7 @@
         // the list: if any subsequent entry matches or widens entry n,
         // remove entry n. If any subsequent entries narrow entry n, remove
         // the subsequent entries.
-        for (int i = 0; i < size(); i++) {
+        for (int i = 0; i < (size() - 1); i++) {
             GeneralNameInterface current = getGeneralNameInterface(i);
             boolean remove1 = false;
 
diff --git a/ojluni/src/main/java/sun/security/x509/IPAddressName.java b/ojluni/src/main/java/sun/security/x509/IPAddressName.java
index 084a6f3..e558c9e 100644
--- a/ojluni/src/main/java/sun/security/x509/IPAddressName.java
+++ b/ojluni/src/main/java/sun/security/x509/IPAddressName.java
@@ -197,8 +197,10 @@
 
             // append a mask corresponding to the num of prefix bits specified
             int prefixLen = Integer.parseInt(name.substring(slashNdx+1));
-            if (prefixLen > 128)
-                throw new IOException("IPv6Address prefix is longer than 128");
+            if (prefixLen < 0 || prefixLen > 128) {
+                throw new IOException("IPv6Address prefix length (" +
+                        prefixLen + ") in out of valid range [0,128]");
+            }
 
             // create new bit array initialized to zeros
             BitArray bitArray = new BitArray(MASKSIZE * 8);
@@ -317,7 +319,8 @@
         if (!(obj instanceof IPAddressName))
             return false;
 
-        byte[] other = ((IPAddressName)obj).getBytes();
+        IPAddressName otherName = (IPAddressName)obj;
+        byte[] other = otherName.address;
 
         if (other.length != address.length)
             return false;
@@ -326,12 +329,10 @@
             // Two subnet addresses
             // Mask each and compare masked values
             int maskLen = address.length/2;
-            byte[] maskedThis = new byte[maskLen];
-            byte[] maskedOther = new byte[maskLen];
             for (int i=0; i < maskLen; i++) {
-                maskedThis[i] = (byte)(address[i] & address[i+maskLen]);
-                maskedOther[i] = (byte)(other[i] & other[i+maskLen]);
-                if (maskedThis[i] != maskedOther[i]) {
+                byte maskedThis = (byte)(address[i] & address[i+maskLen]);
+                byte maskedOther = (byte)(other[i] & other[i+maskLen]);
+                if (maskedThis != maskedOther) {
                     return false;
                 }
             }
@@ -400,7 +401,8 @@
         else if (((IPAddressName)inputName).equals(this))
             constraintType = NAME_MATCH;
         else {
-            byte[] otherAddress = ((IPAddressName)inputName).getBytes();
+            IPAddressName otherName = (IPAddressName)inputName;
+            byte[] otherAddress = otherName.address;
             if (otherAddress.length == 4 && address.length == 4)
                 // Two host addresses
                 constraintType = NAME_SAME_TYPE;
diff --git a/ojluni/src/main/java/sun/security/x509/IssuingDistributionPointExtension.java b/ojluni/src/main/java/sun/security/x509/IssuingDistributionPointExtension.java
index 6a93258..6fe8eb3 100644
--- a/ojluni/src/main/java/sun/security/x509/IssuingDistributionPointExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/IssuingDistributionPointExtension.java
@@ -261,6 +261,7 @@
                 throw new IOException(
                     "Attribute value should be of type ReasonFlags.");
             }
+            revocationReasons = (ReasonFlags)obj;
 
         } else if (name.equalsIgnoreCase(INDIRECT_CRL)) {
             if (!(obj instanceof Boolean)) {
@@ -290,7 +291,6 @@
             }
             hasOnlyAttributeCerts = ((Boolean)obj).booleanValue();
 
-
         } else {
             throw new IOException("Attribute name [" + name +
                 "] not recognized by " +
diff --git a/ojluni/src/main/java/sun/security/x509/KeyIdentifier.java b/ojluni/src/main/java/sun/security/x509/KeyIdentifier.java
index 01d4803..016fd4e 100644
--- a/ojluni/src/main/java/sun/security/x509/KeyIdentifier.java
+++ b/ojluni/src/main/java/sun/security/x509/KeyIdentifier.java
@@ -148,7 +148,7 @@
             return true;
         if (!(other instanceof KeyIdentifier))
             return false;
-        return java.util.Arrays.equals(octetString,
-                                       ((KeyIdentifier)other).getIdentifier());
+        byte[] otherString = ((KeyIdentifier)other).octetString;
+        return java.util.Arrays.equals(octetString, otherString);
     }
 }
diff --git a/ojluni/src/main/java/sun/security/x509/OIDMap.java b/ojluni/src/main/java/sun/security/x509/OIDMap.java
index 9eed0f2..0e3ae16 100644
--- a/ojluni/src/main/java/sun/security/x509/OIDMap.java
+++ b/ojluni/src/main/java/sun/security/x509/OIDMap.java
@@ -112,6 +112,8 @@
     /** Map String(friendly name) -> OIDInfo(info) */
     private final static Map<String,OIDInfo> nameMap;
 
+    // BEGIN Android-changed: Specify Class objects rather for oidMap rather than String
+    // literals + reflection.
     static {
         oidMap = new HashMap<ObjectIdentifier,OIDInfo>();
         nameMap = new HashMap<String,OIDInfo>();
@@ -200,6 +202,8 @@
             return clazz;
         }
     }
+    // END Android-changed: Specify Class objects rather for oidMap rather than String
+    // literals + reflection.
 
     /**
      * Add a name to lookup table.
diff --git a/ojluni/src/main/java/sun/security/x509/PolicyMappingsExtension.java b/ojluni/src/main/java/sun/security/x509/PolicyMappingsExtension.java
index fba5104..e259826 100644
--- a/ojluni/src/main/java/sun/security/x509/PolicyMappingsExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/PolicyMappingsExtension.java
@@ -102,7 +102,7 @@
     public PolicyMappingsExtension() {
         extensionId = PKIXExtensions.KeyUsage_Id;
         critical = false;
-        maps = new ArrayList<CertificatePolicyMap>();
+        maps = Collections.<CertificatePolicyMap>emptyList();
     }
 
     /**
diff --git a/ojluni/src/main/java/sun/security/x509/PrivateKeyUsageExtension.java b/ojluni/src/main/java/sun/security/x509/PrivateKeyUsageExtension.java
index c20d855..512880b 100644
--- a/ojluni/src/main/java/sun/security/x509/PrivateKeyUsageExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/PrivateKeyUsageExtension.java
@@ -33,6 +33,7 @@
 import java.security.cert.CertificateNotYetValidException;
 import java.util.Date;
 import java.util.Enumeration;
+import java.util.Objects;
 
 import sun.security.util.*;
 
@@ -206,16 +207,17 @@
      */
     public void valid(Date now)
     throws CertificateNotYetValidException, CertificateExpiredException {
+        Objects.requireNonNull(now);
         /*
          * we use the internal Dates rather than the passed in Date
          * because someone could override the Date methods after()
          * and before() to do something entirely different.
          */
-        if (notBefore.after(now)) {
+        if (notBefore != null && notBefore.after(now)) {
             throw new CertificateNotYetValidException("NotBefore: " +
                                                       notBefore.toString());
         }
-        if (notAfter.before(now)) {
+        if (notAfter != null && notAfter.before(now)) {
             throw new CertificateExpiredException("NotAfter: " +
                                                   notAfter.toString());
         }
diff --git a/ojluni/src/main/java/sun/security/x509/RDN.java b/ojluni/src/main/java/sun/security/x509/RDN.java
index ed46abe..3bfc524 100644
--- a/ojluni/src/main/java/sun/security/x509/RDN.java
+++ b/ojluni/src/main/java/sun/security/x509/RDN.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@
 
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.Arrays;
+import java.util.StringJoiner;
 import java.util.*;
 
 import sun.security.util.*;
@@ -443,31 +445,19 @@
                                assertion[0].toRFC2253String(oidMap);
         }
 
-        StringBuilder relname = new StringBuilder();
-        if (!canonical) {
-            for (int i = 0; i < assertion.length; i++) {
-                if (i > 0) {
-                    relname.append('+');
-                }
-                relname.append(assertion[i].toRFC2253String(oidMap));
-            }
-        } else {
+        AVA[] toOutput = assertion;
+        if (canonical) {
             // order the string type AVA's alphabetically,
             // followed by the oid type AVA's numerically
-            List<AVA> avaList = new ArrayList<AVA>(assertion.length);
-            for (int i = 0; i < assertion.length; i++) {
-                avaList.add(assertion[i]);
-            }
-            java.util.Collections.sort(avaList, AVAComparator.getInstance());
-
-            for (int i = 0; i < avaList.size(); i++) {
-                if (i > 0) {
-                    relname.append('+');
-                }
-                relname.append(avaList.get(i).toRFC2253CanonicalString());
-            }
+            toOutput = assertion.clone();
+            Arrays.sort(toOutput, AVAComparator.getInstance());
         }
-        return relname.toString();
+        StringJoiner sj = new StringJoiner("+");
+        for (AVA ava : toOutput) {
+            sj.add(canonical ? ava.toRFC2253CanonicalString()
+                             : ava.toRFC2253String(oidMap));
+        }
+        return sj.toString();
     }
 
 }
@@ -488,11 +478,11 @@
      * AVA's containing a standard keyword are ordered alphabetically,
      * followed by AVA's containing an OID keyword, ordered numerically
      */
-    @Override
     public int compare(AVA a1, AVA a2) {
         boolean a1Has2253 = a1.hasRFC2253Keyword();
         boolean a2Has2253 = a2.hasRFC2253Keyword();
 
+        // BEGIN Android-changed: Keep sort order of RDN from Android M
         if (a1Has2253) {
             if (a2Has2253) {
                 return a1.toRFC2253CanonicalString().compareTo
@@ -516,6 +506,7 @@
                         a1Oid[pos] - a2Oid[pos];
             }
         }
+        // BEGIN Android-changed: Keep sort order of RDN from prev impl
     }
 
 }
diff --git a/ojluni/src/main/java/sun/security/x509/SubjectInfoAccessExtension.java b/ojluni/src/main/java/sun/security/x509/SubjectInfoAccessExtension.java
index 2f851f7..e1a0bc2 100644
--- a/ojluni/src/main/java/sun/security/x509/SubjectInfoAccessExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/SubjectInfoAccessExtension.java
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 
+import java.util.Collections;
 import java.util.*;
 
 import sun.security.util.DerOutputStream;
@@ -200,7 +201,8 @@
      */
     public void delete(String name) throws IOException {
         if (name.equalsIgnoreCase(DESCRIPTIONS)) {
-            accessDescriptions = new ArrayList<AccessDescription>();
+            accessDescriptions =
+                Collections.<AccessDescription>emptyList();
         } else {
             throw new IOException("Attribute name [" + name +
                                 "] not recognized by " +
diff --git a/ojluni/src/main/java/sun/security/x509/URIName.java b/ojluni/src/main/java/sun/security/x509/URIName.java
index 034117e..5f4021e 100644
--- a/ojluni/src/main/java/sun/security/x509/URIName.java
+++ b/ojluni/src/main/java/sun/security/x509/URIName.java
@@ -165,7 +165,7 @@
             String host = uri.getSchemeSpecificPart();
             try {
                 DNSName hostDNS;
-                if (host.charAt(0) == '.') {
+                if (host.startsWith(".")) {
                     hostDNS = new DNSName(host.substring(1));
                 } else {
                     hostDNS = new DNSName(host);
diff --git a/ojluni/src/main/java/sun/security/x509/X500Name.java b/ojluni/src/main/java/sun/security/x509/X500Name.java
index 6090554..e708837 100644
--- a/ojluni/src/main/java/sun/security/x509/X500Name.java
+++ b/ojluni/src/main/java/sun/security/x509/X500Name.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -347,6 +347,8 @@
             for (int i = 0; i < names.length; i++) {
                 list.addAll(names[i].avas());
             }
+            list = Collections.unmodifiableList(list);
+            allAvaList = list;
         }
         return list;
     }
@@ -365,9 +367,6 @@
      */
     public boolean isEmpty() {
         int n = names.length;
-        if (n == 0) {
-            return true;
-        }
         for (int i = 0; i < n; i++) {
             if (names[i].assertion.length != 0) {
                 return false;
@@ -877,6 +876,7 @@
             return;
         }
 
+        // Android-added: refuse DN starting with new line or tab
         checkNoNewLinesNorTabsAtBeginningOfDN(input);
 
         List<RDN> dnVector = new ArrayList<>();
@@ -945,6 +945,7 @@
         names = dnVector.toArray(new RDN[dnVector.size()]);
     }
 
+    // BEGIN Android-added: refuse DN starting with new line or tab
     /**
      * Disallow new lines and tabs at the beginning of DN.
      *
@@ -961,6 +962,7 @@
             }
         }
     }
+    // END Android-added: refuse DN starting with new line or tab
 
     private void parseRFC2253DN(String dnString) throws IOException {
         if (dnString.length() == 0) {
@@ -1020,6 +1022,7 @@
     static int countQuotes(String string, int from, int to) {
         int count = 0;
 
+        // BEGIN Android-changed: Fix countQuotes in case of escaped backslashes: \\"
         int escape = 0;
         for (int i = from; i < to; i++) {
             if (string.charAt(i) == '"' && escape % 2 == 0) {
@@ -1027,6 +1030,7 @@
             }
             escape = (string.charAt(i) == '\\') ? escape + 1 : 0;
         }
+        // END Android-changed: Fix countQuotes in case of escaped backslashes: \\"
 
         return count;
     }
@@ -1130,12 +1134,8 @@
      * and speed recognition of common X.500 attributes.
      */
     static ObjectIdentifier intern(ObjectIdentifier oid) {
-        ObjectIdentifier interned = internedOIDs.get(oid);
-        if (interned != null) {
-            return interned;
-        }
-        internedOIDs.put(oid, oid);
-        return oid;
+        ObjectIdentifier interned = internedOIDs.putIfAbsent(oid, oid);
+        return (interned == null) ? oid : interned;
     }
 
     private static final Map<ObjectIdentifier,ObjectIdentifier> internedOIDs
diff --git a/ojluni/src/main/java/sun/security/x509/X509AttributeName.java b/ojluni/src/main/java/sun/security/x509/X509AttributeName.java
index 090792a..c60b6f4 100644
--- a/ojluni/src/main/java/sun/security/x509/X509AttributeName.java
+++ b/ojluni/src/main/java/sun/security/x509/X509AttributeName.java
@@ -47,7 +47,7 @@
      */
     public X509AttributeName(String name) {
         int i = name.indexOf(SEPARATOR);
-        if (i == (-1)) {
+        if (i < 0) {
             prefix = name;
         } else {
             prefix = name.substring(0, i);
diff --git a/ojluni/src/main/java/sun/security/x509/X509CRLImpl.java b/ojluni/src/main/java/sun/security/x509/X509CRLImpl.java
index 52e9818..e0021c8 100644
--- a/ojluni/src/main/java/sun/security/x509/X509CRLImpl.java
+++ b/ojluni/src/main/java/sun/security/x509/X509CRLImpl.java
@@ -748,9 +748,7 @@
     public byte[] getTBSCertList() throws CRLException {
         if (tbsCertList == null)
             throw new CRLException("Uninitialized CRL");
-        byte[] dup = new byte[tbsCertList.length];
-        System.arraycopy(tbsCertList, 0, dup, 0, dup.length);
-        return dup;
+        return tbsCertList.clone();
     }
 
     /**
@@ -761,9 +759,7 @@
     public byte[] getSignature() {
         if (signature == null)
             return null;
-        byte[] dup = new byte[signature.length];
-        System.arraycopy(signature, 0, dup, 0, dup.length);
-        return dup;
+        return signature.clone();
     }
 
     /**
diff --git a/ojluni/src/main/java/sun/security/x509/X509CertImpl.java b/ojluni/src/main/java/sun/security/x509/X509CertImpl.java
index de4d313..57a8f71 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
+    // BEGIN Android-removed: unused code
     /*
     /**
      * unmarshals an X.509 certificate from an input stream.  If the
@@ -266,7 +266,7 @@
                         der = new DerValue(decstream.toByteArray());
                         break;
                     } else {
-                        decstream.write(Base64.getMimeDecoder().decode(line));
+                        decstream.write(Pem.decode(line));
                     }
                 }
             } catch (IOException ioe2) {
@@ -280,7 +280,7 @@
         return der;
     }
     */
-    // END Android-removed
+    // END Android-removed: unused code
 
     /**
      * Construct an initialized X509 Certificate. The certificate is stored
@@ -310,6 +310,7 @@
         }
     }
 
+    // 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
@@ -327,6 +328,7 @@
             throw new CertificateException("Unable to initialize, " + e, e);
         }
     }
+    // END Android-added: Ctor to retain original encoded form for APKs parsing
 
     /**
      * Appends the certificate to an output stream.
@@ -1023,9 +1025,7 @@
     public byte[] getSignature() {
         if (signature == null)
             return null;
-        byte[] dup = new byte[signature.length];
-        System.arraycopy(signature, 0, dup, 0, dup.length);
-        return dup;
+        return signature.clone();
     }
 
     /**
@@ -1784,6 +1784,7 @@
      */
     private void parse(DerValue val)
     throws CertificateException, IOException {
+    // BEGIN Android-added: Use original encoded form of cert rather than regenerating.
         parse(
             val,
             null // use re-encoded form of val as the encoded form
@@ -1802,6 +1803,8 @@
      */
     private void parse(DerValue val, byte[] originalEncodedForm)
     throws CertificateException, IOException {
+    // END Android-added: Use original encoded form of cert rather than regenerating.
+
         // check if can over write the certificate
         if (readOnly)
             throw new CertificateParsingException(
@@ -1811,6 +1814,8 @@
             throw new CertificateParsingException(
                       "invalid DER-encoded certificate data");
 
+        // Android-changed: Needed for providing encoded form of cert
+        // signedCert = val.toByteArray();
         signedCert =
                 (originalEncodedForm != null)
                         ? originalEncodedForm : val.toByteArray();
diff --git a/ojluni/src/main/java/sun/security/x509/X509Key.java b/ojluni/src/main/java/sun/security/x509/X509Key.java
index 109cedf..789b7b8 100644
--- a/ojluni/src/main/java/sun/security/x509/X509Key.java
+++ b/ojluni/src/main/java/sun/security/x509/X509Key.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@
 import java.security.Key;
 import java.security.PublicKey;
 import java.security.KeyFactory;
-import java.security.KeyRep;
 import java.security.Security;
 import java.security.Provider;
 import java.security.InvalidKeyException;
@@ -80,6 +79,7 @@
      * Added to keep the byte[] key form consistent with the BitArray
      * form. Can de deleted when byte[] key is deleted.
      */
+    @Deprecated
     private int unusedBits = 0;
 
     /* BitArray form of key */
@@ -245,7 +245,7 @@
                 throw new InstantiationException();
             }
 
-            Class keyClass = null;
+            Class<?> keyClass = null;
             try {
                 keyClass = Class.forName(classname);
             } catch (ClassNotFoundException e) {
diff --git a/ojluni/src/main/java/sun/util/calendar/AbstractCalendar.java b/ojluni/src/main/java/sun/util/calendar/AbstractCalendar.java
index 96e2e3d..ead18de 100644
--- a/ojluni/src/main/java/sun/util/calendar/AbstractCalendar.java
+++ b/ojluni/src/main/java/sun/util/calendar/AbstractCalendar.java
@@ -123,9 +123,15 @@
         TimeZone zi = date.getZone();
         if (zi != null) {
             int[] offsets = new int[2];
-            zoneOffset = zi.getOffset(millis);
-            offsets[0] = zi.getRawOffset();
-            offsets[1] = zoneOffset - offsets[0];
+            // BEGIN Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            // if (zi instanceof ZoneInfo) {
+            //    zoneOffset = ((ZoneInfo)zi).getOffsets(millis, offsets);
+            // } else {
+                zoneOffset = zi.getOffset(millis);
+                offsets[0] = zi.getRawOffset();
+                offsets[1] = zoneOffset - offsets[0];
+            // }
+            // END Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
 
             // We need to calculate the given millis and time zone
             // offset separately for java.util.GregorianCalendar
@@ -185,14 +191,25 @@
                 // 2) 5:00pm during DST is still interpreted as 5:00pm ST
                 // 3) 1:30am during ending-DST transition is interpreted
                 //    as 1:30am ST (after transition)
-                zoneOffset = zi.getOffset(ms - zi.getRawOffset());
+                // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+                // if (zi instanceof ZoneInfo) {
+                //     ((ZoneInfo)zi).getOffsetsByStandard(ms, offsets);
+                //     zoneOffset = offsets[0];
+                // } else {
+                    zoneOffset = zi.getOffset(ms - zi.getRawOffset());
+                // }
             } else {
                 // 1) 2:30am during starting-DST transition is
                 //    intrepreted as 3:30am DT
                 // 2) 5:00pm during DST is intrepreted as 5:00pm DT
                 // 3) 1:30am during ending-DST transition is interpreted
                 //    as 1:30am DT/0:30am ST (before transition)
-                zoneOffset = zi.getOffset(ms - zi.getRawOffset());
+                // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+                // if (zi instanceof ZoneInfo) {
+                //     zoneOffset = ((ZoneInfo)zi).getOffsetsByWall(ms, offsets);
+                // } else {
+                    zoneOffset = zi.getOffset(ms - zi.getRawOffset());
+                // }
             }
         }
         ms -= zoneOffset;
diff --git a/ojluni/src/main/java/sun/util/calendar/BaseCalendar.java b/ojluni/src/main/java/sun/util/calendar/BaseCalendar.java
index 908bec8..a7e763a 100644
--- a/ojluni/src/main/java/sun/util/calendar/BaseCalendar.java
+++ b/ojluni/src/main/java/sun/util/calendar/BaseCalendar.java
@@ -25,7 +25,6 @@
 
 package sun.util.calendar;
 
-import java.util.Locale;
 import java.util.TimeZone;
 
 /**
diff --git a/ojluni/src/main/java/sun/util/calendar/CalendarDate.java b/ojluni/src/main/java/sun/util/calendar/CalendarDate.java
index 205415e..b8e736c 100644
--- a/ojluni/src/main/java/sun/util/calendar/CalendarDate.java
+++ b/ojluni/src/main/java/sun/util/calendar/CalendarDate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -435,7 +435,7 @@
             return super.clone();
         } catch (CloneNotSupportedException e) {
             // this shouldn't happen
-            throw new InternalError();
+            throw new InternalError(e);
         }
     }
 
diff --git a/ojluni/src/main/java/sun/util/calendar/CalendarSystem.java b/ojluni/src/main/java/sun/util/calendar/CalendarSystem.java
index 58707fb..3b9cbf7 100644
--- a/ojluni/src/main/java/sun/util/calendar/CalendarSystem.java
+++ b/ojluni/src/main/java/sun/util/calendar/CalendarSystem.java
@@ -75,25 +75,53 @@
 
     /////////////////////// Calendar Factory Methods /////////////////////////
 
+    // BEGIN Android-changed: avoid reflection for loading calendar classes.
+    // // Map of calendar names and calendar class names
+    // private static ConcurrentMap<String, String> names;
     // Map of calendar names and calendar classes;
     private static final Map<String, Class<?>> names;
 
-    // Android-changed: Don't use reflection for Class.forName every time.
+    // Map of calendar names and CalendarSystem instances
+    private static final ConcurrentMap<String, CalendarSystem> calendars =
+            new ConcurrentHashMap<>();
 
     static {
         names = new HashMap<>();
         names.put("gregorian", Gregorian.class);
         names.put("japanese", LocalGregorianCalendar.class);
         names.put("julian", JulianCalendar.class);
-        // names.put("hebrew", "HebrewCalendar");
-        // names.put("iso8601", "ISOCalendar");
-        // names.put("taiwanese", "LocalGregorianCalendar");
-        // names.put("thaibuddhist", "LocalGregorianCalendar");
+    // END Android-changed: avoid reflection for loading calendar classes.
+        /*
+        "hebrew", "HebrewCalendar",
+        "iso8601", "ISOCalendar",
+        "taiwanese", "LocalGregorianCalendar",
+        "thaibuddhist", "LocalGregorianCalendar",
+        */
     }
 
-    // Map of calendar names and CalendarSystem instances
-    private static final ConcurrentMap<String, CalendarSystem> calendars =
-            new ConcurrentHashMap<>();
+    // BEGIN Android-removed: avoid reflection for loading calendar classes.
+    /*
+    private static void initNames() {
+        ConcurrentMap<String,String> nameMap = new ConcurrentHashMap<>();
+
+        // Associate a calendar name with its class name and the
+        // calendar class name with its date class name.
+        StringBuilder clName = new StringBuilder();
+        for (int i = 0; i < namePairs.length; i += 2) {
+            clName.setLength(0);
+            String cl = clName.append(PACKAGE_NAME).append(namePairs[i+1]).toString();
+            nameMap.put(namePairs[i], cl);
+        }
+        synchronized (CalendarSystem.class) {
+            if (!initialized) {
+                names = nameMap;
+                calendars = new ConcurrentHashMap<>();
+                initialized = true;
+            }
+        }
+    }
+    */
+    // END Android-removed: avoid reflection for loading calendar classes.
 
     private final static Gregorian GREGORIAN_INSTANCE = new Gregorian();
 
@@ -122,7 +150,7 @@
             return GREGORIAN_INSTANCE;
         }
 
-        //Android-changed: remove lazy initialization, use classes instead of class names.
+        // Android-changed: remove lazy initialization, use classes instead of class names.
 
         CalendarSystem cal = calendars.get(calendarName);
         if (cal != null) {
@@ -141,13 +169,12 @@
             try {
                 cal = (CalendarSystem) calendarClass.newInstance();
             } catch (Exception e) {
-                throw new RuntimeException("internal error", e);
+                throw new InternalError(e);
             }
         }
         if (cal == null) {
             return null;
         }
-
         CalendarSystem cs =  calendars.putIfAbsent(calendarName, cal);
         return (cs == null) ? cal : cs;
     }
@@ -161,7 +188,7 @@
      *                                  Unicode escape sequences
      */
     public static Properties getCalendarProperties() throws IOException {
-        // Android-changed: load from resources.
+        // Android-changed: load calendar Properties from resources.
         Properties calendarProps = new Properties();
         try (InputStream is = ClassLoader.getSystemResourceAsStream("calendars.properties")) {
             calendarProps.load(is);
diff --git a/ojluni/src/main/java/sun/util/calendar/LocalGregorianCalendar.java b/ojluni/src/main/java/sun/util/calendar/LocalGregorianCalendar.java
index 4d0922d..3c969a7 100644
--- a/ojluni/src/main/java/sun/util/calendar/LocalGregorianCalendar.java
+++ b/ojluni/src/main/java/sun/util/calendar/LocalGregorianCalendar.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,7 @@
 
 package sun.util.calendar;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
@@ -60,6 +54,7 @@
 
         private int gregorianYear = FIELD_UNDEFINED;
 
+        @Override
         public Date setEra(Era era) {
             if (getEra() != era) {
                 super.setEra(era);
@@ -68,12 +63,14 @@
             return this;
         }
 
+        @Override
         public Date addYear(int localYear) {
             super.addYear(localYear);
             gregorianYear += localYear;
             return this;
         }
 
+        @Override
         public Date setYear(int localYear) {
             if (getYear() != localYear) {
                 super.setYear(localYear);
@@ -82,10 +79,12 @@
             return this;
         }
 
+        @Override
         public int getNormalizedYear() {
             return gregorianYear;
         }
 
+        @Override
         public void setNormalizedYear(int normalizedYear) {
             this.gregorianYear = normalizedYear;
         }
@@ -98,6 +97,7 @@
             super.setYear(year);
         }
 
+        @Override
         public String toString() {
             String time = super.toString();
             time = time.substring(time.indexOf('T'));
@@ -118,20 +118,18 @@
     }
 
     static LocalGregorianCalendar getLocalGregorianCalendar(String name) {
-        // Android-changed: use getCalendarProperties()
         Properties calendarProps;
         try {
-            calendarProps = getCalendarProperties();
-        } catch (IOException e) {
-            throw new RuntimeException(e);
+            calendarProps = CalendarSystem.getCalendarProperties();
+        } catch (IOException | IllegalArgumentException e) {
+            throw new InternalError(e);
         }
-
         // Parse calendar.*.eras
         String props = calendarProps.getProperty("calendar." + name + ".eras");
         if (props == null) {
             return null;
         }
-        List<Era> eras = new ArrayList<Era>();
+        List<Era> eras = new ArrayList<>();
         StringTokenizer eraTokens = new StringTokenizer(props, ";");
         while (eraTokens.hasMoreTokens()) {
             String items = eraTokens.nextToken().trim();
@@ -168,11 +166,12 @@
             Era era = new Era(eraName, abbr, since, localTime);
             eras.add(era);
         }
-        // Android-changed: Throw if no eras were found, as other code depends on there being
-        // at least one era.
+        // BEGIN Android-changed: Require at least one era.
+        // Other code depends on there being at least one era.
         if (eras.isEmpty()) {
             throw new RuntimeException("No eras for " + name);
         }
+        // END Android-changed: Require at least one era.
         Era[] eraArray = new Era[eras.size()];
         eras.toArray(eraArray);
 
@@ -185,22 +184,27 @@
         setEras(eras);
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
+    @Override
     public Date getCalendarDate() {
         return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
     }
 
+    @Override
     public Date getCalendarDate(long millis) {
         return getCalendarDate(millis, newCalendarDate());
     }
 
+    @Override
     public Date getCalendarDate(long millis, TimeZone zone) {
         return getCalendarDate(millis, newCalendarDate(zone));
     }
 
+    @Override
     public Date getCalendarDate(long millis, CalendarDate date) {
         Date ldate = (Date) super.getCalendarDate(millis, date);
         return adjustYear(ldate, millis, ldate.getZoneOffset());
@@ -229,14 +233,17 @@
         return ldate;
     }
 
+    @Override
     public Date newCalendarDate() {
         return new Date();
     }
 
+    @Override
     public Date newCalendarDate(TimeZone zone) {
         return new Date(zone);
     }
 
+    @Override
     public boolean validate(CalendarDate date) {
         Date ldate = (Date) date;
         Era era = ldate.getEra();
@@ -270,6 +277,7 @@
         return false;
     }
 
+    @Override
     public boolean normalize(CalendarDate date) {
         if (date.isNormalized()) {
             return true;
@@ -343,6 +351,7 @@
         return true;
     }
 
+    @Override
     void normalizeMonth(CalendarDate date) {
         normalizeYear(date);
         super.normalizeMonth(date);
@@ -364,6 +373,7 @@
      * Returns whether the specified Gregorian year is a leap year.
      * @see #isLeapYear(Era, int)
      */
+    @Override
     public boolean isLeapYear(int gregorianYear) {
         return CalendarUtils.isGregorianLeapYear(gregorianYear);
     }
@@ -376,6 +386,7 @@
         return isLeapYear(gyear);
     }
 
+    @Override
     public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
         Date ldate = (Date) date;
         super.getCalendarDateFromFixedDate(ldate, fixedDate);
diff --git a/ojluni/src/main/java/sun/util/locale/BaseLocale.java b/ojluni/src/main/java/sun/util/locale/BaseLocale.java
index 6eee582..e0e9ed0 100644
--- a/ojluni/src/main/java/sun/util/locale/BaseLocale.java
+++ b/ojluni/src/main/java/sun/util/locale/BaseLocale.java
@@ -31,6 +31,7 @@
  */
 
 package sun.util.locale;
+import java.lang.ref.SoftReference;
 
 
 public final class BaseLocale {
@@ -163,11 +164,11 @@
         return h;
     }
 
-    private static final class Key implements Comparable<Key> {
-        private final String lang;
-        private final String scrt;
-        private final String regn;
-        private final String vart;
+    private static final class Key {
+        private final SoftReference<String> lang;
+        private final SoftReference<String> scrt;
+        private final SoftReference<String> regn;
+        private final SoftReference<String> vart;
         private final boolean normalized;
         private final int hash;
 
@@ -179,10 +180,10 @@
             assert language.intern() == language
                    && region.intern() == region;
 
-            lang = language;
-            scrt = "";
-            regn = region;
-            vart = "";
+            lang = new SoftReference(language);
+            scrt = new SoftReference("");
+            regn = new SoftReference(region);
+            vart = new SoftReference("");
             this.normalized = true;
 
             int h = language.hashCode();
@@ -203,40 +204,40 @@
                     String variant, boolean normalized) {
             int h = 0;
             if (language != null) {
-                lang = language;
+                lang = new SoftReference(language);
                 int len = language.length();
                 for (int i = 0; i < len; i++) {
                     h = 31*h + LocaleUtils.toLower(language.charAt(i));
                 }
             } else {
-                lang = "";
+                lang = new SoftReference("");
             }
             if (script != null) {
-                scrt = script;
+                scrt = new SoftReference(script);
                 int len = script.length();
                 for (int i = 0; i < len; i++) {
                     h = 31*h + LocaleUtils.toLower(script.charAt(i));
                 }
             } else {
-                scrt = "";
+                scrt = new SoftReference("");
             }
             if (region != null) {
-                regn = region;
+                regn = new SoftReference(region);
                 int len = region.length();
                 for (int i = 0; i < len; i++) {
                     h = 31*h + LocaleUtils.toLower(region.charAt(i));
                 }
             } else {
-                regn = "";
+                regn = new SoftReference("");
             }
             if (variant != null) {
-                vart = variant;
+                vart = new SoftReference(variant);
                 int len = variant.length();
                 for (int i = 0; i < len; i++) {
                     h = 31*h + variant.charAt(i);
                 }
             } else {
-                vart = "";
+                vart = new SoftReference("");
             }
             hash = h;
             this.normalized = normalized;
@@ -244,28 +245,31 @@
 
         @Override
         public boolean equals(Object obj) {
-            return (this == obj) ||
-                    (obj instanceof Key)
-                    && this.hash == ((Key)obj).hash
-                    && LocaleUtils.caseIgnoreMatch(((Key)obj).lang, this.lang)
-                    && LocaleUtils.caseIgnoreMatch(((Key)obj).scrt, this.scrt)
-                    && LocaleUtils.caseIgnoreMatch(((Key)obj).regn, this.regn)
-                    && ((Key)obj).vart.equals(vart); // variant is case sensitive in JDK!
+            if (this == obj) {
+                return true;
         }
 
-        @Override
-        public int compareTo(Key other) {
-            int res = LocaleUtils.caseIgnoreCompare(this.lang, other.lang);
-            if (res == 0) {
-                res = LocaleUtils.caseIgnoreCompare(this.scrt, other.scrt);
-                if (res == 0) {
-                    res = LocaleUtils.caseIgnoreCompare(this.regn, other.regn);
-                    if (res == 0) {
-                        res = this.vart.compareTo(other.vart);
+            if (obj instanceof Key && this.hash == ((Key)obj).hash) {
+                String tl = this.lang.get();
+                String ol = ((Key)obj).lang.get();
+                if (tl != null && ol != null &&
+                    LocaleUtils.caseIgnoreMatch(ol, tl)) {
+                    String ts = this.scrt.get();
+                    String os = ((Key)obj).scrt.get();
+                    if (ts != null && os != null &&
+                        LocaleUtils.caseIgnoreMatch(os, ts)) {
+                        String tr = this.regn.get();
+                        String or = ((Key)obj).regn.get();
+                        if (tr != null && or != null &&
+                            LocaleUtils.caseIgnoreMatch(or, tr)) {
+                            String tv = this.vart.get();
+                            String ov = ((Key)obj).vart.get();
+                            return (ov != null && ov.equals(tv));
                     }
                 }
             }
-            return res;
+            }
+            return false;
         }
 
         @Override
@@ -278,10 +282,10 @@
                 return key;
             }
 
-            String lang = LocaleUtils.toLowerString(key.lang).intern();
-            String scrt = LocaleUtils.toTitleString(key.scrt).intern();
-            String regn = LocaleUtils.toUpperString(key.regn).intern();
-            String vart = key.vart.intern(); // preserve upper/lower cases
+            String lang = LocaleUtils.toLowerString(key.lang.get()).intern();
+            String scrt = LocaleUtils.toTitleString(key.scrt.get()).intern();
+            String regn = LocaleUtils.toUpperString(key.regn.get()).intern();
+            String vart = key.vart.get().intern(); // preserve upper/lower cases
 
             return new Key(lang, scrt, regn, vart, true);
         }
@@ -294,12 +298,18 @@
 
         @Override
         protected Key normalizeKey(Key key) {
+            assert key.lang.get() != null &&
+                   key.scrt.get() != null &&
+                   key.regn.get() != null &&
+                   key.vart.get() != null;
+
             return Key.normalize(key);
         }
 
         @Override
         protected BaseLocale createObject(Key key) {
-            return new BaseLocale(key.lang, key.scrt, key.regn, key.vart);
+            return new BaseLocale(key.lang.get(), key.scrt.get(),
+                                  key.regn.get(), key.vart.get());
         }
     }
 }
diff --git a/ojluni/src/main/java/sun/util/locale/InternalLocaleBuilder.java b/ojluni/src/main/java/sun/util/locale/InternalLocaleBuilder.java
index 378fb6c..81fa86e 100644
--- a/ojluni/src/main/java/sun/util/locale/InternalLocaleBuilder.java
+++ b/ojluni/src/main/java/sun/util/locale/InternalLocaleBuilder.java
@@ -419,8 +419,9 @@
         }
 
         if (variant.length() > 0) {
-            // normalize separators to "_"
+            // BEGIN Android-added: normalize separators to "_"
             variant = variant.replaceAll(LanguageTag.SEP, BaseLocale.SEP);
+            // END Android-added: normalize separators to "_"
             int errIdx = checkVariants(variant, BaseLocale.SEP);
             if (errIdx != -1) {
                 throw new LocaleSyntaxException("Ill-formed variant: " + variant, errIdx);
diff --git a/ojluni/src/main/java/sun/util/locale/LanguageTag.java b/ojluni/src/main/java/sun/util/locale/LanguageTag.java
index fc7b07b..2247398 100644
--- a/ojluni/src/main/java/sun/util/locale/LanguageTag.java
+++ b/ojluni/src/main/java/sun/util/locale/LanguageTag.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -134,7 +134,7 @@
     }
 
     /*
-     * BNF in RFC5464
+     * BNF in RFC5646
      *
      * Language-Tag  = langtag             ; normal language tags
      *               / privateuse          ; private use tag
diff --git a/ojluni/src/main/java/sun/util/locale/LocaleMatcher.java b/ojluni/src/main/java/sun/util/locale/LocaleMatcher.java
index 6b5f597..70fabc7 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
             String rangeForRegex = range.replace("*", "\\p{Alnum}*");
             while (rangeForRegex.length() > 0) {
                 for (String tag : tags) {
@@ -242,6 +242,7 @@
     }
 
     public static List<LanguageRange> parse(String ranges) {
+        // 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
@@ -331,6 +332,7 @@
         return list;
     }
 
+    // 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.
@@ -345,6 +347,7 @@
                     + range.substring(pos + substr.length());
         }
     }
+    // END Android-added: backport OpenJDK 9 fix for JDK-8166994
 
     private static String[] getEquivalentsForLanguage(String range) {
         String r = range;
@@ -354,6 +357,9 @@
                 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
+// 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,
                     r, equiv)};
             } else if (LocaleEquivalentMaps.multiEquivsMap.containsKey(r)) {
@@ -364,6 +370,7 @@
                             r, equivs[i]);
                 }
                 return result;
+// END Android-added: backport OpenJDK 9 fix for JDK-8166994
             }
 
             // Truncate the last subtag simply.
diff --git a/ojluni/src/main/java/sun/util/locale/LocaleObjectCache.java b/ojluni/src/main/java/sun/util/locale/LocaleObjectCache.java
index 88920aa..eae1480 100644
--- a/ojluni/src/main/java/sun/util/locale/LocaleObjectCache.java
+++ b/ojluni/src/main/java/sun/util/locale/LocaleObjectCache.java
@@ -57,8 +57,10 @@
             value = entry.get();
         }
         if (value == null) {
-            key = normalizeKey(key);
             V newVal = createObject(key);
+            // make sure key is normalized *after* the object creation
+            // so that newVal is assured to be created from a valid key.
+            key = normalizeKey(key);
             if (key == null || newVal == null) {
                 // subclass must return non-null key/value object
                 return null;
diff --git a/ojluni/src/main/java/sun/util/locale/LocaleUtils.java b/ojluni/src/main/java/sun/util/locale/LocaleUtils.java
index 9a89dc0..ead48fc 100644
--- a/ojluni/src/main/java/sun/util/locale/LocaleUtils.java
+++ b/ojluni/src/main/java/sun/util/locale/LocaleUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/sun/util/logging/LoggingProxy.java b/ojluni/src/main/java/sun/util/logging/LoggingProxy.java
index 9fbcc73..c044a5a 100644
--- a/ojluni/src/main/java/sun/util/logging/LoggingProxy.java
+++ b/ojluni/src/main/java/sun/util/logging/LoggingProxy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/sun/util/logging/LoggingSupport.java b/ojluni/src/main/java/sun/util/logging/LoggingSupport.java
index dd65b74..67b617d 100644
--- a/ojluni/src/main/java/sun/util/logging/LoggingSupport.java
+++ b/ojluni/src/main/java/sun/util/logging/LoggingSupport.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/sun/util/logging/PlatformLogger.java b/ojluni/src/main/java/sun/util/logging/PlatformLogger.java
index f9849c5..1ed8811 100644
--- a/ojluni/src/main/java/sun/util/logging/PlatformLogger.java
+++ b/ojluni/src/main/java/sun/util/logging/PlatformLogger.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -84,22 +84,18 @@
  * @since 1.7
  */
 public class PlatformLogger {
-    /*
-     * These constants should be shortcuts to Level enum constants that
-     * the clients of sun.util.logging.PlatformLogger require no source
-     * modification and avoid the conversion from int to Level enum.
-     *
-     * This can be done when JavaFX is converted to use the new PlatformLogger.Level API.
-     */
-    public static final int OFF     = Integer.MAX_VALUE;
-    public static final int SEVERE  = 1000;
-    public static final int WARNING = 900;
-    public static final int INFO    = 800;
-    public static final int CONFIG  = 700;
-    public static final int FINE    = 500;
-    public static final int FINER   = 400;
-    public static final int FINEST  = 300;
-    public static final int ALL     = Integer.MIN_VALUE;
+
+    // The integer values must match that of {@code java.util.logging.Level}
+    // objects.
+    private static final int OFF     = Integer.MAX_VALUE;
+    private static final int SEVERE  = 1000;
+    private static final int WARNING = 900;
+    private static final int INFO    = 800;
+    private static final int CONFIG  = 700;
+    private static final int FINE    = 500;
+    private static final int FINER   = 400;
+    private static final int FINEST  = 300;
+    private static final int ALL     = Integer.MIN_VALUE;
 
     /**
      * PlatformLogger logging levels.
@@ -126,19 +122,19 @@
         /* java.util.logging.Level */ Object javaLevel;
 
         // ascending order for binary search matching the list of enum constants
-        private static final int[] levelValues = new int[] {
+        private static final int[] LEVEL_VALUES = new int[] {
             PlatformLogger.ALL, PlatformLogger.FINEST, PlatformLogger.FINER,
             PlatformLogger.FINE, PlatformLogger.CONFIG, PlatformLogger.INFO,
             PlatformLogger.WARNING, PlatformLogger.SEVERE, PlatformLogger.OFF
         };
 
         public int intValue() {
-            return levelValues[this.ordinal()];
+            return LEVEL_VALUES[this.ordinal()];
         }
 
         static Level valueOf(int level) {
             switch (level) {
-                // ordering per the highest occurences in the jdk source
+                // ordering per the highest occurrences in the jdk source
                 // finest, fine, finer, info first
                 case PlatformLogger.FINEST  : return Level.FINEST;
                 case PlatformLogger.FINE    : return Level.FINE;
@@ -152,7 +148,7 @@
             }
             // return the nearest Level value >= the given level,
             // for level > SEVERE, return SEVERE and exclude OFF
-            int i = Arrays.binarySearch(levelValues, 0, levelValues.length-2, level);
+            int i = Arrays.binarySearch(LEVEL_VALUES, 0, LEVEL_VALUES.length-2, level);
             return values()[i >= 0 ? i : (-i-1)];
         }
     }
@@ -169,23 +165,22 @@
                 }
             });
 
-        // Android-removed: Unnecessary on android, and gets in the way of obfuscated
-        // releases.
-        //
+        // Android-removed: JavaLoggerProxy is unneeded, complicates obfuscated releases.
+        /*
         // force loading of all JavaLoggerProxy (sub)classes to make JIT de-optimizations
         // less probable.  Don't initialize JavaLoggerProxy class since
         // java.util.logging may not be enabled.
-        //
-        // try {
-        //     Class.forName("sun.util.logging.PlatformLogger$DefaultLoggerProxy",
-        //                   false,
-        //                   PlatformLogger.class.getClassLoader());
-        //     Class.forName("sun.util.logging.PlatformLogger$JavaLoggerProxy",
-        //                   false,   // do not invoke class initializer
-        //                   PlatformLogger.class.getClassLoader());
-        // } catch (ClassNotFoundException ex) {
-        //     throw new InternalError(ex.getMessage());
-        // }
+        try {
+            Class.forName("sun.util.logging.PlatformLogger$DefaultLoggerProxy",
+                          false,
+                          PlatformLogger.class.getClassLoader());
+            Class.forName("sun.util.logging.PlatformLogger$JavaLoggerProxy",
+                          false,   // do not invoke class initializer
+                          PlatformLogger.class.getClassLoader());
+        } catch (ClassNotFoundException ex) {
+            throw new InternalError(ex);
+        }
+        */
     }
 
     // Table of known loggers.  Maps names to PlatformLoggers.
@@ -267,39 +262,6 @@
     /**
      * Returns true if a message of the given level would actually
      * be logged by this logger.
-     *
-     * @deprecated Use isLoggable(Level) instead.
-     */
-    @Deprecated
-    public boolean isLoggable(int levelValue) {
-        return isLoggable(Level.valueOf(levelValue));
-    }
-
-    /**
-     * Gets the current log level. Returns 0 if the current effective level is
-     * not set (equivalent to Logger.getLevel() returns null).
-     *
-     * @deprecated Use level() instead
-     */
-    @Deprecated
-    public int getLevel() {
-        Level level = loggerProxy.getLevel();
-        return level != null ? level.intValue() : 0;
-    }
-
-    /**
-     * Sets the log level.
-     *
-     * @deprecated Use setLevel(Level) instead
-     */
-    @Deprecated
-    public void setLevel(int newLevel) {
-        loggerProxy.setLevel(newLevel == 0 ? null : Level.valueOf(newLevel));
-    }
-
-    /**
-     * Returns true if a message of the given level would actually
-     * be logged by this logger.
      */
     public boolean isLoggable(Level level) {
         if (level == null) {
@@ -588,6 +550,16 @@
 
             String logClassName = "sun.util.logging.PlatformLogger";
             boolean lookingForLogger = true;
+            // Android-changed: Different way to access throwable.getStackTrace()
+            // OpenJDK's faster way via SharedSecrets.getJavaLangAccess()
+            // is not available on Android.
+            /*
+            for (int ix = 0; ix < depth; ix++) {
+                // Calling getStackTraceElement directly prevents the VM
+                // from paying the cost of building the entire stack frame.
+                StackTraceElement frame =
+                    access.getStackTraceElement(throwable, ix);
+            */
             for (StackTraceElement frame : throwable.getStackTrace()) {
                 String cname = frame.getClassName();
                 if (lookingForLogger) {
diff --git a/ojluni/src/main/java/sun/util/resources/OpenListResourceBundle.java b/ojluni/src/main/java/sun/util/resources/OpenListResourceBundle.java
index 86a91f8..462b0a7 100644
--- a/ojluni/src/main/java/sun/util/resources/OpenListResourceBundle.java
+++ b/ojluni/src/main/java/sun/util/resources/OpenListResourceBundle.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,7 @@
 
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.ResourceBundle;
 import java.util.Set;
@@ -66,7 +67,8 @@
     }
 
     // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
-    public Object handleGetObject(String key) {
+    @Override
+    protected Object handleGetObject(String key) {
         if (key == null) {
             throw new NullPointerException();
         }
@@ -78,26 +80,39 @@
     /**
      * Implementation of ResourceBundle.getKeys.
      */
+    @Override
     public Enumeration<String> getKeys() {
-        ResourceBundle parent = this.parent;
-        return new ResourceBundleEnumeration(handleGetKeys(),
-                (parent != null) ? parent.getKeys() : null);
-    }
+        ResourceBundle parentBundle = this.parent;
+        return new ResourceBundleEnumeration(handleKeySet(),
+                (parentBundle != null) ? parentBundle.getKeys() : null);
+     }
 
     /**
-     * Returns a set of keys provided in this resource bundle
+     * Returns a set of keys provided in this resource bundle,
+     * including no parents.
      */
-    public Set<String> handleGetKeys() {
+    @Override
+    protected Set<String> handleKeySet() {
         loadLookupTablesIfNecessary();
-
         return lookup.keySet();
     }
 
-    /**
-     * Returns the parent bundle
-     */
-    public OpenListResourceBundle getParent() {
-        return (OpenListResourceBundle)parent;
+    @Override
+    public Set<String> keySet() {
+        if (keyset != null) {
+            return keyset;
+        }
+        Set<String> ks = createSet();
+        ks.addAll(handleKeySet());
+        if (parent != null) {
+            ks.addAll(parent.keySet());
+        }
+        synchronized (this) {
+            if (keyset == null) {
+                keyset = ks;
+            }
+        }
+        return keyset;
     }
 
     /**
@@ -118,12 +133,9 @@
      * We lazily load the lookup hashtable.  This function does the
      * loading.
      */
-    private synchronized void loadLookup() {
-        if (lookup != null)
-            return;
-
+    private void loadLookup() {
         Object[][] contents = getContents();
-        Map temp = createMap(contents.length);
+        Map<String, Object> temp = createMap(contents.length);
         for (int i = 0; i < contents.length; ++i) {
             // key must be non-null String, value must be non-null
             String key = (String) contents[i][0];
@@ -133,16 +145,25 @@
             }
             temp.put(key, value);
         }
-        lookup = temp;
+        synchronized (this) {
+            if (lookup == null) {
+                lookup = temp;
+            }
+        }
     }
 
     /**
      * Lets subclasses provide specialized Map implementations.
      * Default uses HashMap.
      */
-    protected Map createMap(int size) {
-        return new HashMap(size);
+    protected <K, V> Map<K, V> createMap(int size) {
+        return new HashMap<>(size);
     }
 
-    private Map lookup = null;
+    protected <E> Set<E> createSet() {
+        return new HashSet<>();
+    }
+
+    private volatile Map<String, Object> lookup = null;
+    private volatile Set<String> keyset;
 }
diff --git a/ojluni/src/main/native/NativeThread.c b/ojluni/src/main/native/NativeThread.c
index f8a68e7..9147bc3 100644
--- a/ojluni/src/main/native/NativeThread.c
+++ b/ojluni/src/main/native/NativeThread.c
@@ -35,8 +35,10 @@
 #ifdef __linux__
   #include <pthread.h>
   #include <sys/signal.h>
+  // Android-changed: Bionic (and AsynchronousCloseMonitor) expects libcore to use
+  // __SIGRTMIN + 2, not __SIGRTMAX - 2
   /* Also defined in net/linux_close.c */
-  #define INTERRUPT_SIGNAL (__SIGRTMAX - 2)
+  #define INTERRUPT_SIGNAL (__SIGRTMIN + 2)
 #elif __solaris__
   #include <thread.h>
   #include <signal.h>
diff --git a/ojluni/src/main/native/System.c b/ojluni/src/main/native/System.c
index e75e01c..22c4d52 100644
--- a/ojluni/src/main/native/System.c
+++ b/ojluni/src/main/native/System.c
@@ -244,10 +244,6 @@
     }
 
     WITH_PLATFORM_STRING(env, javaMessage, message) {
-      if (message == NULL) {
-          // Since this function is used for last-gasp debugging output, be noisy on failure.
-          return;
-      }
       LOG_PRI(priority, "System", "%s", message);
     } END_PLATFORM_STRING(env, message);
 
diff --git a/ojluni/src/main/native/java_net_SocketOptions.h b/ojluni/src/main/native/java_net_SocketOptions.h
deleted file mode 100644
index e428bb5..0000000
--- a/ojluni/src/main/native/java_net_SocketOptions.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* This file was generated from java/net/SocketOptions.java and is licensed
- * under the same terms. The copyright and license information for
- * java/net/SocketOptions.java follows.
- *
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class java_net_SocketOptions */
-
-#ifndef _Included_java_net_SocketOptions
-#define _Included_java_net_SocketOptions
-#ifdef __cplusplus
-extern "C" {
-#endif
-#undef java_net_SocketOptions_TCP_NODELAY
-#define java_net_SocketOptions_TCP_NODELAY 1L
-#undef java_net_SocketOptions_SO_BINDADDR
-#define java_net_SocketOptions_SO_BINDADDR 15L
-#undef java_net_SocketOptions_SO_REUSEADDR
-#define java_net_SocketOptions_SO_REUSEADDR 4L
-#undef java_net_SocketOptions_SO_BROADCAST
-#define java_net_SocketOptions_SO_BROADCAST 32L
-#undef java_net_SocketOptions_IP_MULTICAST_IF
-#define java_net_SocketOptions_IP_MULTICAST_IF 16L
-#undef java_net_SocketOptions_IP_MULTICAST_IF2
-#define java_net_SocketOptions_IP_MULTICAST_IF2 31L
-#undef java_net_SocketOptions_IP_MULTICAST_LOOP
-#define java_net_SocketOptions_IP_MULTICAST_LOOP 18L
-#undef java_net_SocketOptions_IP_TOS
-#define java_net_SocketOptions_IP_TOS 3L
-#undef java_net_SocketOptions_SO_LINGER
-#define java_net_SocketOptions_SO_LINGER 128L
-#undef java_net_SocketOptions_SO_TIMEOUT
-#define java_net_SocketOptions_SO_TIMEOUT 4102L
-#undef java_net_SocketOptions_SO_SNDBUF
-#define java_net_SocketOptions_SO_SNDBUF 4097L
-#undef java_net_SocketOptions_SO_RCVBUF
-#define java_net_SocketOptions_SO_RCVBUF 4098L
-#undef java_net_SocketOptions_SO_KEEPALIVE
-#define java_net_SocketOptions_SO_KEEPALIVE 8L
-#undef java_net_SocketOptions_SO_OOBINLINE
-#define java_net_SocketOptions_SO_OOBINLINE 4099L
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/ojluni/src/main/native/linux_close.cpp b/ojluni/src/main/native/linux_close.cpp
index e9a2588..6f88c93 100644
--- a/ojluni/src/main/native/linux_close.cpp
+++ b/ojluni/src/main/native/linux_close.cpp
@@ -45,7 +45,9 @@
 /*
  * Signal to unblock thread
  */
-static int sigWakeup = (__SIGRTMAX - 2);
+// Android-changed: Bionic (and AsynchronousCloseMonitor) expects libcore to use
+// __SIGRTMIN + 2, not __SIGRTMAX - 2
+static int sigWakeup = (__SIGRTMIN + 2);
 
 /*
  * Close or dup2 a file descriptor ensuring that all threads blocked on
diff --git a/ojluni/src/main/native/net_util.h b/ojluni/src/main/native/net_util.h
index 839e947..afd94ed 100644
--- a/ojluni/src/main/native/net_util.h
+++ b/ojluni/src/main/native/net_util.h
@@ -78,6 +78,8 @@
 extern jclass ia4_class;
 extern jmethodID ia4_ctrID;
 
+/* Android-removed: NetworkInterface moved away fro JNI */
+#if 0
 /* NetworkInterface fields */
 extern jclass ni_class;
 extern jfieldID ni_nameID;
@@ -85,13 +87,17 @@
 extern jfieldID ni_addrsID;
 extern jfieldID ni_descID;
 extern jmethodID ni_ctrID;
+#endif
 
+/* Android-removed: PlainSocketImpl moved away fro JNI */
+#if 0
 /* PlainSocketImpl fields */
 extern jfieldID psi_timeoutID;
 extern jfieldID psi_fdID;
 extern jfieldID psi_addressID;
 extern jfieldID psi_portID;
 extern jfieldID psi_localportID;
+#endif
 
 /* Android-removed: DatagramSocket moved away from JNI */
 #if 0
@@ -138,8 +144,11 @@
 void initLocalAddrTable ();
 void parseExclusiveBindProperty(JNIEnv *env);
 
+// Android-removed: unused
+#if 0
 void
 NET_SetTrafficClass(struct sockaddr *him, int trafficClass);
+#endif
 
 JNIEXPORT jint JNICALL
 NET_GetPortFromSockaddr(struct sockaddr *him);
@@ -156,8 +165,11 @@
 int
 NET_IsEqual(jbyte* caddr1, jbyte* caddr2);
 
+// Android-removed: unused
+#if 0
 int
 NET_IsZeroAddr(jbyte* caddr);
+#endif
 
 /* Socket operations
  *
@@ -174,11 +186,14 @@
 JNIEXPORT int JNICALL
 NET_Bind(int fd, struct sockaddr *him, int len);
 
+// Android-removed: unused
+#if 0
 JNIEXPORT int JNICALL
 NET_MapSocketOption(jint cmd, int *level, int *optname);
 
 JNIEXPORT int JNICALL
 NET_MapSocketOptionV6(jint cmd, int *level, int *optname);
+#endif
 
 int getScopeID (struct sockaddr *);
 
diff --git a/ojluni/src/main/native/net_util_md.c b/ojluni/src/main/native/net_util_md.c
index 49c9779..d15e29d 100644
--- a/ojluni/src/main/native/net_util_md.c
+++ b/ojluni/src/main/native/net_util_md.c
@@ -64,7 +64,11 @@
 #include "jvm.h"
 #include "net_util.h"
 
+// Android-removed: unused
+#if 0
 #include "java_net_SocketOptions.h"
+#endif
+
 
 /* needed from libsocket on Solaris 8 */
 
@@ -83,6 +87,8 @@
 #define UDP_EXCLBIND            0x0101
 #endif
 
+// Android-removed: unused
+#if 0
 void setDefaultScopeID(JNIEnv *env, struct sockaddr *him)
 {
 #ifdef MACOSX
@@ -124,6 +130,7 @@
                                                  ni_defaultIndexID);
     return defaultIndex;
 }
+#endif
 
 #ifdef __solaris__
 static int init_tcp_max_buf, init_udp_max_buf;
@@ -817,6 +824,8 @@
     return 0;
 }
 
+// Android-removed: unused
+#if 0
 void
 NET_SetTrafficClass(struct sockaddr *him, int trafficClass) {
 #ifdef AF_INET6
@@ -826,6 +835,7 @@
     }
 #endif /* AF_INET6 */
 }
+#endif
 
 JNIEXPORT jint JNICALL
 NET_GetPortFromSockaddr(struct sockaddr *him) {
@@ -876,6 +886,8 @@
     return (jboolean)(getaddrinfo_ptr != NULL);
 }
 
+// Android-removed: unused
+#if 0
 int NET_IsZeroAddr(jbyte* caddr) {
     int i;
     for (i = 0; i < 16; i++) {
@@ -885,7 +897,10 @@
     }
     return 1;
 }
+#endif
 
+// Android-removed: unused
+#if 0
 /*
  * Map the Java level socket option to the platform specific
  * level and option name.
@@ -952,6 +967,7 @@
     /* not found */
     return -1;
 }
+#endif
 
 /*
  * Wrapper for getsockopt system routine - does any necessary
@@ -1321,6 +1337,8 @@
     return rv;
 }
 
+// Android-removed: unused
+#if 0
 /**
  * Wrapper for select/poll with timeout on a single file descriptor.
  *
@@ -1399,6 +1417,7 @@
 
     return timeout;
 }
+#endif
 
 #if 0
 // Stripped out unused code.
diff --git a/ojluni/src/main/native/net_util_md.h b/ojluni/src/main/native/net_util_md.h
index 46fa8dd..5c6dd42 100644
--- a/ojluni/src/main/native/net_util_md.h
+++ b/ojluni/src/main/native/net_util_md.h
@@ -112,7 +112,10 @@
 #define NET_WAIT_WRITE  0x02
 #define NET_WAIT_CONNECT        0x04
 
+// Android-removed: unused
+#if 0
 extern jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout);
+#endif
 
 /************************************************************************
  * Macros and constants
@@ -149,10 +152,13 @@
 /************************************************************************
  *  Utilities
  */
+// Android-removed: unused
+#if 0
 #ifdef __linux__
 extern int kernelIsV22();
 extern int kernelIsV24();
 #endif
+#endif
 
 void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
                    const char *defaultDetail);
diff --git a/ojluni/src/test/java/security/cert/PKIXCertPathValidatorValidity.java b/ojluni/src/test/java/security/cert/PKIXCertPathValidatorValidity.java
new file mode 100644
index 0000000..fd68b44
--- /dev/null
+++ b/ojluni/src/test/java/security/cert/PKIXCertPathValidatorValidity.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/**
+ * @test
+ * @bug 8021804
+ * @summary CertPath should validate even if the validity period of the
+ *          root cert does not include the validity period of a subordinate
+ *          cert.
+ */
+// Android-changed: Adapted from
+// jdk/test/sun/security/provider/certpath/PKIXCertPathValidator/Validity.java
+// Android-changed: Added package & Test import
+package test.java.security.cert;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.security.cert.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+// Android-changed: s/Validity/PKIXCertPathValidatorValidity
+public class PKIXCertPathValidatorValidity {
+
+    /*
+     * Subject: OU=TestOrg, CN=TestCA
+     * Issuer: OU=TestOrg, CN=TestCA
+     * Validity
+     *     Not Before: Feb 26 21:33:55 2014 GMT
+           Not After : Feb 26 21:33:55 2024 GMT
+     * Version 1
+     */
+    static String CACertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBvTCCASYCCQCQRiTo4lBCFjANBgkqhkiG9w0BAQUFADAjMRAwDgYDVQQLDAdU\n" +
+        "ZXN0T3JnMQ8wDQYDVQQDDAZUZXN0Q0EwHhcNMTQwMjI2MjEzMzU1WhcNMjQwMjI2\n" +
+        "MjEzMzU1WjAjMRAwDgYDVQQLDAdUZXN0T3JnMQ8wDQYDVQQDDAZUZXN0Q0EwgZ8w\n" +
+        "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOtKS4ZrsM3ansd61ZxitcrN0w184I+A\n" +
+        "z0kyrSP1eMtlam+cC2U91NpTz11FYV4XUfBhqqxaXW043AWTUer8pS90Pt4sCrUX\n" +
+        "COx1+QA1M3ZhbZ4sTM7XQ90JbGaBJ/sEza9mlQP7hQ2yQO/hATKbP6J5qvgG2sT2\n" +
+        "S2WYjEgwNwmFAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAQ/CXEpnx2WY4LJtv4jwE\n" +
+        "4jIVirur3pdzV5oBhPyqqHMsyhQBkukCfX7uD7L5wN1+xuM81DfANpIxlnUfybp5\n" +
+        "CpjcmktLpmyK4kJ6XnSd2blbLOIpsr9x6FqxPxpVDlyw/ySHYrIG/GZdsLHgmzGn\n" +
+        "B06jeYzH8OLf879VxAxSsPc=\n" +
+        "-----END CERTIFICATE-----";
+
+    /*
+     * Subject: OU=TestOrg, CN=TestEE0
+     * Issuer: OU=TestOrg, CN=TestCA
+     * Validity
+     *     Not Before: Feb 26 22:55:12 2014 GMT
+     *     Not After : Feb 25 22:55:12 2025 GMT
+     * Version 1
+     */
+    static String EECertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBtjCCAR8CAQQwDQYJKoZIhvcNAQEFBQAwIzEQMA4GA1UECwwHVGVzdE9yZzEP\n" +
+        "MA0GA1UEAwwGVGVzdENBMB4XDTE0MDIyNjIyNTUxMloXDTI1MDIyNTIyNTUxMlow\n" +
+        "JDEQMA4GA1UECwwHVGVzdE9yZzEQMA4GA1UEAwwHVGVzdEVFMDCBnzANBgkqhkiG\n" +
+        "9w0BAQEFAAOBjQAwgYkCgYEAt8xz9W3ruCTHjSOtTX6cxsUZ0nRP6EavEfzgcOYh\n" +
+        "CXGA0gr+viSHq3c2vQBxiRny2hm5rLcqpPo+2OxZtw/ajxfyrV6d/r8YyQLBvyl3\n" +
+        "xdCZdOkG1DCM1oFAQDaSRt9wN5Zm5kyg7uMig5Y4L45fP9Yee4x6Xyh36qYbsR89\n" +
+        "rFMCAwEAATANBgkqhkiG9w0BAQUFAAOBgQDZrPqSo08va1m9TOWOztTuWilGdjK/\n" +
+        "2Ed2WXg8utIpy6uAV+NaOYtHQ7ULQBVRNmwg9nKghbVbh+E/xpoihjl1x7OXass4\n" +
+        "TbwXA5GKFIFpNtDvATQ/QQZoCuCzw1FW/mH0Q7UEQ/9/iJdDad6ebkapeMwtj/8B\n" +
+        "s2IZV7s85CEOXw==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() throws Exception {
+
+        String[] certStrs = {EECertStr};
+        String[] trustedCertStrs = {CACertStr};
+        runTest(certStrs, trustedCertStrs);
+
+        System.out.println("Test passed.");
+    }
+
+    private static void runTest(String[] certStrs,
+                                String[] trustedCertStrs)
+            throws Exception {
+
+        CertificateFactory cf = CertificateFactory.getInstance("X509");
+
+        // Generate the CertPath from the certs named in certStrs
+        ArrayList<X509Certificate> certs = new ArrayList<>();
+        for (String certStr : certStrs) {
+            certs.add(generateCert(certStr, cf));
+        }
+        CertPath cp = cf.generateCertPath(certs);
+
+        // Generate the set of Trust Anchors from the certs named in
+        // trustedCertStrs
+        Set<TrustAnchor> trustAnchors = new HashSet<>();
+        for (String trustedCertStr : trustedCertStrs) {
+            TrustAnchor ta = new TrustAnchor(generateCert(trustedCertStr, cf),
+                                             null);
+            trustAnchors.add(ta);
+        }
+        PKIXParameters params = new PKIXParameters(trustAnchors);
+        params.setDate(new Date(114, 3, 1));   // 2014-03-01
+        params.setRevocationEnabled(false);
+
+        // Attempt to validate the CertPath. If no exception thrown, successful.
+        CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
+        cpv.validate(cp, params);
+        System.out.println("CertPath validation successful.");
+    }
+
+    private static X509Certificate generateCert(String certStr,
+                                                CertificateFactory cf)
+            throws Exception {
+        ByteArrayInputStream stream
+                = new ByteArrayInputStream(certStr.getBytes());
+        return (X509Certificate) cf.generateCertificate(stream);
+
+    }
+}
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index a812e07..81110ab 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -152,7 +152,6 @@
     ojluni/src/main/java/java/lang/InternalError.java \
     ojluni/src/main/java/java/lang/InterruptedException.java \
     ojluni/src/main/java/java/lang/Iterable.java \
-    ojluni/src/main/java/java/lang/JavaLangAccess.java \
     ojluni/src/main/java/java/lang/LinkageError.java \
     ojluni/src/main/java/java/lang/Long.java \
     ojluni/src/main/java/java/lang/Math.java \
@@ -1342,6 +1341,26 @@
     ojluni/src/main/java/javax/sql/StatementEventListener.java \
     ojluni/src/main/java/sun/reflect/CallerSensitive.java \
 
+# Stubs needed to satisfy javac's dependencies when compiling lambda code. These are
+# not used on Android devices or required by the Jack compiler.
+#
+# On aosp/master:
+# openjdk_lambda_stub_files : These are included in core-oj as stubs
+# openjdk_lambda_duplicate_stub_files : These contain complete implementations in core-oj.
+#
+# On older platforms : Both sets of stub files are used and core-oj does not contain
+# any of these classes.
+openjdk_lambda_stub_files := \
+    ojluni/src/lambda/java/java/lang/invoke/LambdaMetafactory.java \
+    ojluni/src/lambda/java/java/lang/invoke/SerializedLambda.java
+openjdk_lambda_duplicate_stub_files := \
+    ojluni/src/lambda/java/java/lang/invoke/CallSite.java \
+    ojluni/src/lambda/java/java/lang/invoke/MethodHandles.java \
+    ojluni/src/lambda/java/java/lang/invoke/LambdaConversionException.java \
+    ojluni/src/lambda/java/java/lang/invoke/MethodHandle.java \
+    ojluni/src/lambda/java/java/lang/invoke/MethodType.java \
+
+
 # NOTE: Files in java/lang/invoke are listed here because they're not being made public
 # until the entire package is available for use.
 openjdk_java_files := \
@@ -1378,7 +1397,6 @@
     ojluni/src/main/java/sun/misc/FloatConsts.java \
     ojluni/src/main/java/sun/misc/FormattedFloatingDecimal.java \
     ojluni/src/main/java/sun/misc/FpUtils.java \
-    ojluni/src/main/java/sun/misc/Hashing.java \
     ojluni/src/main/java/sun/misc/HexDumpEncoder.java \
     ojluni/src/main/java/sun/misc/InvalidJarIndexException.java \
     ojluni/src/main/java/sun/misc/IOUtils.java \
@@ -1738,21 +1756,3 @@
     $(openjdk_javadoc_files) \
     $(openjdk_lambda_stub_files)
 
-# Stubs needed to satisfy javac's dependencies when compiling lambda code. These are
-# not used on Android devices or required by the Jack compiler.
-#
-# On aosp/master:
-# openjdk_lambda_stub_files : These are included in core-oj as stubs
-# openjdk_lambda_duplicate_stub_files : These contain complete implementations in core-oj.
-#
-# On older platforms : Both sets of stub files are used and core-oj does not contain
-# any of these classes.
-openjdk_lambda_stub_files := \
-    ojluni/src/lambda/java/java/lang/invoke/LambdaMetafactory.java \
-    ojluni/src/lambda/java/java/lang/invoke/SerializedLambda.java
-openjdk_lambda_duplicate_stub_files := \
-    ojluni/src/lambda/java/java/lang/invoke/CallSite.java \
-    ojluni/src/lambda/java/java/lang/invoke/MethodHandles.java \
-    ojluni/src/lambda/java/java/lang/invoke/LambdaConversionException.java \
-    ojluni/src/lambda/java/java/lang/invoke/MethodHandle.java \
-    ojluni/src/lambda/java/java/lang/invoke/MethodType.java \
diff --git a/tools/docs/crypto/README b/tools/docs/crypto/README
index cc6b6eb..9a34b7f 100644
--- a/tools/docs/crypto/README
+++ b/tools/docs/crypto/README
@@ -2,7 +2,8 @@
 
 The central file is data/crypto_support.json, which is a JSON file that contains
 the supported API levels for each crypto algorithm that has ever been supported
-by Android.  The categories are identified as described in the JCA.
+by Android.  The categories are identified as described in the JCA, along with
+a couple extra classes.
 
 Each algorithm has up to three properties:
 
@@ -24,9 +25,8 @@
 
 Getting the set of supported algorithms is done using
 src/java/libcore/java/security/ListProviders.java.  It's important that this is
-run using vogar (in mode=device, the default) rather than in an app container,
-as this documentation only includes the libcore-supported crypto support, but
-the Android frameworks (in particular, Android KeyStore) can add additional
+run using vogar in mode=activity rather than the default of mode=device, as
+the Android frameworks (in particular, Android Keystore) can add additional
 support.
 
 The data from ListProviders is fed into update_crypto_support.py, which rewrites
@@ -38,4 +38,5 @@
 
 Finally, format_supported_algorithm_table.py reads the data file and outputs
 a collection of HTML tables suitable for copying-and-pasting into the docs
-to stdout.
+to stdout.  Add --javadoc to produce output appropriate for inclusion in
+Javadoc.
diff --git a/tools/upstream/oj_upstream_comparison.py b/tools/upstream/oj_upstream_comparison.py
index deab5fb..76d63aa 100755
--- a/tools/upstream/oj_upstream_comparison.py
+++ b/tools/upstream/oj_upstream_comparison.py
@@ -85,43 +85,34 @@
             return result
     return None
 
-
-# For files with N and M lines, respectively, this runs in time
-# O(N+M) if the files are identical or O(N*M) if not. This could
-# be improved to O(D*(N+M)) for files with at most D lines
-# difference by only considering array elements within D cells
-# from the diagonal.
-def edit_distance_lines(file_a, file_b):
+# For lists of length N and M, respectively, this runs in time O(N*M).
+# This could be improved to O(D*(N+M)) for lists with distance <= D by
+# only considering array elements within D cells of the diagonal.
+def edit_distance(a, b):
     """
-    Computes the line-based edit distance between two text files, i.e.
-    the smallest number of line deletions, additions or replacements
-    that would transform the content of one file into that of the other.
+    Computes the line-based edit distance between two lists, i.e.
+    the smallest number of list items to delete, insert or replace
+    that would transform the content of one list into the other.
     """
-    if filecmp.cmp(file_a, file_b, shallow=False):
-        return 0 # files identical
-    with open(file_a) as f:
-        lines_a = f.readlines()
-    with open(file_b) as f:
-        lines_b = f.readlines()
-    prev_cost = range(0, len(lines_b) + 1)
-    for end_a in range(1, len(lines_a) + 1):
+    prev_cost = range(0, len(b) + 1)
+    for end_a in range(1, len(a) + 1):
         # For each valid index i, prev_cost[i] is the edit distance between
-        # lines_a[:end_a-1] and lines_b[:i].
+        # a[:end_a-1] and b[:i].
         # We now calculate cur_cost[end_b] as the edit distance between
-        # line_a[:end_a] and lines_b[:end_b]
+        # a[:end_a] and b[:end_b]
         cur_cost = [end_a]
-        for end_b in range(1, len(lines_b) + 1):
+        for end_b in range(1, len(b) + 1):
             c = min(
-                cur_cost[-1] + 1, # append line from b
-                prev_cost[end_b] + 1, # append line from a
-                # match or replace line
-                prev_cost[end_b - 1] + (0 if lines_a[end_a - 1] == lines_b[end_b - 1] else 1)
+                cur_cost[-1] + 1, # append item from b
+                prev_cost[end_b] + 1, # append item from a
+                # match or replace item
+                prev_cost[end_b - 1] + (0 if a[end_a - 1] == b[end_b - 1] else 1)
                 )
             cur_cost.append(c)
         prev_cost = cur_cost
     return prev_cost[-1]
 
-def compare_to_upstreams_and_save(out_file, build_top, upstream_root, upstreams, rel_paths, best_only=False):
+def compare_to_upstreams_and_save(out_file, build_top, upstream_root, upstreams, rel_paths):
     """
     Prints tab-separated values comparing ojluni files vs. each
     upstream, for each of the rel_paths, suitable for human
@@ -144,13 +135,21 @@
             if upstream_file is None:
                 upstream_comparison = "missing"
             else:
-                edit_distance = edit_distance_lines(upstream_file, ojluni_file)
-                if edit_distance == 0:
+                if filecmp.cmp(upstream_file, ojluni_file, shallow=False):
+                    distance = 0
                     upstream_comparison = "identical"
                 else:
-                    upstream_comparison = "different (%d lines)" % (edit_distance)
-                if edit_distance < best_distance:
-                    best_distance = edit_distance
+                    with open(upstream_file) as f:
+                        lines_a = f.readlines()
+                    with open(ojluni_file) as f:
+                        lines_b = f.readlines()
+                    distance = edit_distance(lines_a, lines_b)
+                    # 0% for identical files
+                    # 100% for totally different files or where one file is empty
+                    percent_different = 100.0 * distance / max(len(lines_a), len(lines_b))
+                    upstream_comparison = "%.1f%% different (%d lines)" % (percent_different, distance)
+                if distance < best_distance:
+                    best_distance = distance
                     guessed_upstream = upstream
             upstream_comparisons.append(upstream_comparison)
         writer.writerow([rel_path, guessed_upstream ] + upstream_comparisons)