am 97452bf6: Merge "Test fallback SHA1PRNG uses full width seeds" into jb-dev

* commit '97452bf60c7324c96ddf8ba6e14055c55065b406':
  Test fallback SHA1PRNG uses full width seeds
diff --git a/CaCerts.mk b/CaCerts.mk
index cdced8f..980d0fb 100644
--- a/CaCerts.mk
+++ b/CaCerts.mk
@@ -30,6 +30,7 @@
 define include-prebuilt-with-destination-directory
 include $$(CLEAR_VARS)
 LOCAL_MODULE := $(1)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/CaCerts.mk
 LOCAL_MODULE_STEM := $(notdir $(2))
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 18fa870..59ac2e1 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -82,6 +82,7 @@
 LOCAL_NO_EMMA_COMPILE := true
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := core
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
 
 include $(BUILD_JAVA_LIBRARY)
 
@@ -98,6 +99,7 @@
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE := core-tests
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
 LOCAL_NO_EMMA_INSTRUMENT := true
 LOCAL_NO_EMMA_COMPILE := true
 include $(BUILD_STATIC_JAVA_LIBRARY)
@@ -140,6 +142,7 @@
 
     LOCAL_MODULE_TAGS := optional
     LOCAL_MODULE := core-hostdex
+    LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
 
     include $(BUILD_HOST_JAVA_LIBRARY)
 
@@ -151,8 +154,9 @@
     LOCAL_JAVA_LIBRARIES := bouncycastle-hostdex core-hostdex core-junit-hostdex
     LOCAL_STATIC_JAVA_LIBRARIES := sqlite-jdbc-host mockwebserver-hostdex
     LOCAL_JAVACFLAGS := $(local_javac_flags)
-    LOCAL_MODULE_TAGS := tests
+    LOCAL_MODULE_TAGS := optional
     LOCAL_MODULE := core-tests-hostdex
+    LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
     LOCAL_NO_EMMA_INSTRUMENT := true
     LOCAL_NO_EMMA_COMPILE := true
     LOCAL_BUILD_HOST_DEX := true
@@ -190,6 +194,7 @@
 LOCAL_MODULE_CLASS:=JAVA_LIBRARIES
 
 LOCAL_MODULE := libcore
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
 
 LOCAL_DROIDDOC_OPTIONS:= \
  -offlinemode \
diff --git a/NativeCode.mk b/NativeCode.mk
index 2a222b1..1aab901 100644
--- a/NativeCode.mk
+++ b/NativeCode.mk
@@ -53,6 +53,7 @@
 # set up.
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(core_magic_local_target)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
 core_src_files :=
 
 # Include the sub.mk files.
@@ -65,9 +66,6 @@
 core_c_includes := $(sort libcore/include $(LOCAL_C_INCLUDES) $(JNI_H_INCLUDE))
 core_shared_libraries := $(sort $(LOCAL_SHARED_LIBRARIES))
 core_static_libraries := $(sort $(LOCAL_STATIC_LIBRARIES))
-core_cflags := -fvisibility=hidden
-core_cflags += '-DGCC_HIDDEN=__attribute__((visibility("hidden")))'
-core_cppflags := -fvisibility-inlines-hidden
 
 
 #
@@ -91,6 +89,7 @@
 LOCAL_STATIC_LIBRARIES := $(core_static_libraries)
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := libjavacore
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
 
 LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
 LOCAL_SHARED_LIBRARIES += libstlport
@@ -111,6 +110,7 @@
     LOCAL_LDLIBS += -ldl -lpthread
     LOCAL_MODULE_TAGS := optional
     LOCAL_MODULE := libjavacore
+    LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
     LOCAL_SHARED_LIBRARIES := $(core_shared_libraries) libexpat libicuuc libicui18n libssl libcrypto libz-host
     LOCAL_STATIC_LIBRARIES := $(core_static_libraries)
     include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop
deleted file mode 100644
index 9f828fa..0000000
--- a/ThirdPartyProject.prop
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2010 Google Inc. All Rights Reserved.
-#Fri Jul 16 10:03:08 PDT 2010
-currentVersion=5.0M10
-version=Unknown
-isNative=false
-name=apache_harmony
-keywords=apache harmony
-onDevice=true
-homepage=http\://harmony.apache.org/
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index ab24f0b..62ec5e3 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -28,6 +28,9 @@
     /** originally specified path (just used for {@code toString()}) */
     private final String originalPath;
 
+    /** originally specified library path (just used for {@code toString()}) */
+    private final String originalLibraryPath;
+
     /** structured lists of path elements */
     private final DexPathList pathList;
 
@@ -49,6 +52,7 @@
         super(parent);
 
         this.originalPath = dexPath;
+        this.originalLibraryPath = libraryPath;
         this.pathList =
             new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
     }
@@ -58,7 +62,7 @@
         Class clazz = pathList.findClass(name);
 
         if (clazz == null) {
-            throw new ClassNotFoundException(name);
+            throw new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + originalPath);
         }
 
         return clazz;
@@ -123,6 +127,7 @@
 
     @Override
     public String toString() {
-        return getClass().getName() + "[" + originalPath + "]";
+        return getClass().getName()
+                + "[dexPath=" + originalPath + ",libraryPath=" + originalLibraryPath + "]";
     }
 }
diff --git a/dalvik/src/main/java/dalvik/system/CloseGuard.java b/dalvik/src/main/java/dalvik/system/CloseGuard.java
index 136be2f..df36867 100644
--- a/dalvik/src/main/java/dalvik/system/CloseGuard.java
+++ b/dalvik/src/main/java/dalvik/system/CloseGuard.java
@@ -197,7 +197,7 @@
     /**
      * If CloseGuard is enabled, logs a warning if the caller did not
      * properly cleanup by calling an explicit close method
-     * before finalization. If CloseGuard is disable, no action is
+     * before finalization. If CloseGuard is disabled, no action is
      * performed.
      */
     public void warnIfOpen() {
@@ -223,7 +223,7 @@
      * Default Reporter which reports CloseGuard violations to the log.
      */
     private static final class DefaultReporter implements Reporter {
-        public void report (String message, Throwable allocationSite) {
+        @Override public void report (String message, Throwable allocationSite) {
             System.logW(message, allocationSite);
         }
     }
diff --git a/dalvik/src/main/java/dalvik/system/VMRuntime.java b/dalvik/src/main/java/dalvik/system/VMRuntime.java
index c37290d..71098be 100644
--- a/dalvik/src/main/java/dalvik/system/VMRuntime.java
+++ b/dalvik/src/main/java/dalvik/system/VMRuntime.java
@@ -91,7 +91,7 @@
      * @throws IllegalArgumentException if newTarget is <= 0.0 or >= 1.0
      */
     public float setTargetHeapUtilization(float newTarget) {
-        if (newTarget <= 0.0 || newTarget >= 1.0) {
+        if (newTarget <= 0.0f || newTarget >= 1.0f) {
             throw new IllegalArgumentException(newTarget +
                     " out of range (0,1)");
         }
diff --git a/dalvik/src/main/java/dalvik/system/Zygote.java b/dalvik/src/main/java/dalvik/system/Zygote.java
index 28c9912..ec114ed 100644
--- a/dalvik/src/main/java/dalvik/system/Zygote.java
+++ b/dalvik/src/main/java/dalvik/system/Zygote.java
@@ -107,20 +107,23 @@
      * dimension having a length of 3 and representing
      * (resource, rlim_cur, rlim_max). These are set via the posix
      * setrlimit(2) call.
+     * @param seInfo null-ok a string specifying SEAndroid information for
+     * the new process.
+     * @param niceName null-ok a string specifying the process name.
      *
      * @return 0 if this is the child, pid of the child
      * if this is the parent, or -1 on error.
      */
     public static int forkAndSpecialize(int uid, int gid, int[] gids,
-            int debugFlags, int[][] rlimits) {
+            int debugFlags, int[][] rlimits, String seInfo, String niceName) {
         preFork();
-        int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits);
+        int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits, seInfo, niceName);
         postFork();
         return pid;
     }
 
     native public static int nativeForkAndSpecialize(int uid, int gid,
-            int[] gids, int debugFlags, int[][] rlimits);
+            int[] gids, int debugFlags, int[][] rlimits, String seInfo, String niceName);
 
     /**
      * Forks a new VM instance.
@@ -130,7 +133,7 @@
     public static int forkAndSpecialize(int uid, int gid, int[] gids,
             boolean enableDebugger, int[][] rlimits) {
         int debugFlags = enableDebugger ? DEBUG_ENABLE_DEBUGGER : 0;
-        return forkAndSpecialize(uid, gid, gids, debugFlags, rlimits);
+        return forkAndSpecialize(uid, gid, gids, debugFlags, rlimits, null, null);
     }
 
     /**
@@ -175,7 +178,7 @@
     public static int forkSystemServer(int uid, int gid, int[] gids,
             boolean enableDebugger, int[][] rlimits) {
         int debugFlags = enableDebugger ? DEBUG_ENABLE_DEBUGGER : 0;
-        return forkAndSpecialize(uid, gid, gids, debugFlags, rlimits);
+        return forkAndSpecialize(uid, gid, gids, debugFlags, rlimits, null, null);
     }
 
     native public static int nativeForkSystemServer(int uid, int gid,
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index fe110ea..972f1ef 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -89,12 +89,6 @@
   substring: "java.net.URISyntaxException"
 },
 {
-  description: "Test regression",
-  name: "libcore.javax.crypto.spec.KeyFactoryTestDSA#testKeyFactory",
-  substring: "not implemented yet",
-  bug: 3286592
-},
-{
   description: "KxmlParser doesn't expose DTD text",
   name: "libcore.xml.KxmlPullParserDtdTest#testDoctypeWithNextToken",
   bug: 3241492
diff --git a/include/ScopedLocalRef.h b/include/ScopedLocalRef.h
index 84ee11a..71d5776 100644
--- a/include/ScopedLocalRef.h
+++ b/include/ScopedLocalRef.h
@@ -17,28 +17,36 @@
 #ifndef SCOPED_LOCAL_REF_H_included
 #define SCOPED_LOCAL_REF_H_included
 
-#include "JNIHelp.h"
+#include "jni.h"
+
+#include <stddef.h>
 
 // A smart pointer that deletes a JNI local reference when it goes out of scope.
 template<typename T>
 class ScopedLocalRef {
 public:
-    ScopedLocalRef(JNIEnv* env, T localRef)
-    : mEnv(env), mLocalRef(localRef)
-    {
+    ScopedLocalRef(JNIEnv* env, T localRef) : mEnv(env), mLocalRef(localRef) {
     }
 
     ~ScopedLocalRef() {
         reset();
     }
 
-    void reset() {
-        if (mLocalRef != NULL) {
-            mEnv->DeleteLocalRef(mLocalRef);
-            mLocalRef = NULL;
+    void reset(T ptr = NULL) {
+        if (ptr != mLocalRef) {
+            if (mLocalRef != NULL) {
+                mEnv->DeleteLocalRef(mLocalRef);
+            }
+            mLocalRef = ptr;
         }
     }
 
+    T release() __attribute__((warn_unused_result)) {
+        T localRef = mLocalRef;
+        mLocalRef = NULL;
+        return localRef;
+    }
+
     T get() const {
         return mLocalRef;
     }
diff --git a/luni/src/main/files/cacerts/1e1eab7c.0 b/luni/src/main/files/cacerts/1e1eab7c.0
new file mode 100644
index 0000000..a7cf5f9
--- /dev/null
+++ b/luni/src/main/files/cacerts/1e1eab7c.0
@@ -0,0 +1,80 @@
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
+KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
+BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
+YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1
+OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy
+aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50
+ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN
+8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/
+RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4
+hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5
+ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM
+EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1
+A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy
+WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ
+1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30
+6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT
+91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p
+TpPDpFQUWw==
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 3
+        Validity
+            Not Before: Oct  1 10:29:56 2008 GMT
+            Not After : Oct  1 23:59:59 2033 GMT
+        Subject: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 3
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:bd:75:93:f0:62:22:6f:24:ae:e0:7a:76:ac:7d:
+                    bd:d9:24:d5:b8:b7:fc:cd:f0:42:e0:eb:78:88:56:
+                    5e:9b:9a:54:1d:4d:0c:8a:f6:d3:cf:70:f4:52:b5:
+                    d8:93:04:e3:46:86:71:41:4a:2b:f0:2a:2c:55:03:
+                    d6:48:c3:e0:39:38:ed:f2:5c:3c:3f:44:bc:93:3d:
+                    61:ab:4e:cd:0d:be:f0:20:27:58:0e:44:7f:04:1a:
+                    87:a5:d7:96:14:36:90:d0:49:7b:a1:75:fb:1a:6b:
+                    73:b1:f8:ce:a9:09:2c:f2:53:d5:c3:14:44:b8:86:
+                    a5:f6:8b:2b:39:da:a3:33:54:d9:fa:72:1a:f7:22:
+                    15:1c:88:91:6b:7f:66:e5:c3:6a:80:b0:24:f3:df:
+                    86:45:88:fd:19:7f:75:87:1f:1f:b1:1b:0a:73:24:
+                    5b:b9:65:e0:2c:54:c8:60:d3:66:17:3f:e1:cc:54:
+                    33:73:91:02:3a:a6:7f:7b:76:39:a2:1f:96:b6:38:
+                    ae:b5:c8:93:74:1d:9e:b9:b4:e5:60:9d:2f:56:d1:
+                    e0:eb:5e:5b:4c:12:70:0c:6c:44:20:ab:11:d8:f4:
+                    19:f6:d2:9c:52:37:e7:fa:b6:c2:31:3b:4a:d4:14:
+                    99:ad:c7:1a:f5:5d:5f:fa:07:b8:7c:0d:1f:d6:83:
+                    1e:b3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Subject Key Identifier: 
+                B5:03:F7:76:3B:61:82:6A:12:AA:18:53:EB:03:21:94:BF:FE:CE:CA
+    Signature Algorithm: sha256WithRSAEncryption
+        56:3d:ef:94:d5:bd:da:73:b2:58:be:ae:90:ad:98:27:97:fe:
+        01:b1:b0:52:00:b8:4d:e4:1b:21:74:1b:7e:c0:ee:5e:69:2a:
+        25:af:5c:d6:1d:da:d2:79:c9:f3:97:29:e0:86:87:de:04:59:
+        0f:f1:59:d4:64:85:4b:99:af:25:04:1e:c9:46:a9:97:de:82:
+        b2:1b:70:9f:9c:f6:af:71:31:dd:7b:05:a5:2c:d3:b9:ca:47:
+        f6:ca:f2:f6:e7:ad:b9:48:3f:bc:16:b7:c1:6d:f4:ea:09:af:
+        ec:f3:b5:e7:05:9e:a6:1e:8a:53:51:d6:93:81:cc:74:93:f6:
+        b9:da:a6:25:05:74:79:5a:7e:40:3e:82:4b:26:11:30:6e:e1:
+        3f:41:c7:47:00:35:d5:f5:d3:f7:54:3e:81:3d:da:49:6a:9a:
+        b3:ef:10:3d:e6:eb:6f:d1:c8:22:47:cb:cc:cf:01:31:92:d9:
+        18:e3:22:be:09:1e:1a:3e:5a:b2:e4:6b:0c:54:7a:7d:43:4e:
+        b8:89:a5:7b:d7:a2:3d:96:86:cc:f2:26:34:2d:6a:92:9d:9a:
+        1a:d0:30:e2:5d:4e:04:b0:5f:8b:20:7e:77:c1:3d:95:82:d1:
+        46:9a:3b:3c:78:b8:6f:a1:d0:0d:64:a2:78:1e:29:4e:93:c3:
+        a4:54:14:5b
+SHA1 Fingerprint=55:A6:72:3E:CB:F2:EC:CD:C3:23:74:70:19:9D:2A:BE:11:E3:81:D1
diff --git a/luni/src/main/java/java/beans/PropertyChangeSupport.java b/luni/src/main/java/java/beans/PropertyChangeSupport.java
index 04f8155..1db12b7 100644
--- a/luni/src/main/java/java/beans/PropertyChangeSupport.java
+++ b/luni/src/main/java/java/beans/PropertyChangeSupport.java
@@ -66,7 +66,7 @@
      */
     public PropertyChangeSupport(Object sourceBean) {
         if (sourceBean == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("sourceBean == null");
         }
         this.sourceBean = sourceBean;
     }
diff --git a/luni/src/main/java/java/io/BufferedWriter.java b/luni/src/main/java/java/io/BufferedWriter.java
index e4cbe7c..55ae121 100644
--- a/luni/src/main/java/java/io/BufferedWriter.java
+++ b/luni/src/main/java/java/io/BufferedWriter.java
@@ -163,33 +163,33 @@
 
     /**
      * Writes {@code count} characters starting at {@code offset} in
-     * {@code cbuf} to this writer. If {@code count} is greater than this
+     * {@code buffer} to this writer. If {@code count} is greater than this
      * writer's buffer, then the buffer is flushed and the characters are
      * written directly to the target writer.
      *
-     * @param cbuf
+     * @param buffer
      *            the array containing characters to write.
      * @param offset
-     *            the start position in {@code cbuf} for retrieving characters.
+     *            the start position in {@code buffer} for retrieving characters.
      * @param count
      *            the maximum number of characters to write.
      * @throws IndexOutOfBoundsException
      *             if {@code offset < 0} or {@code count < 0}, or if
      *             {@code offset + count} is greater than the size of
-     *             {@code cbuf}.
+     *             {@code buffer}.
      * @throws IOException
      *             if this writer is closed or another I/O error occurs.
      */
     @Override
-    public void write(char[] cbuf, int offset, int count) throws IOException {
+    public void write(char[] buffer, int offset, int count) throws IOException {
         synchronized (lock) {
             checkNotClosed();
-            if (cbuf == null) {
+            if (buffer == null) {
                 throw new NullPointerException("buffer == null");
             }
-            Arrays.checkOffsetAndCount(cbuf.length, offset, count);
+            Arrays.checkOffsetAndCount(buffer.length, offset, count);
             if (pos == 0 && count >= this.buf.length) {
-                out.write(cbuf, offset, count);
+                out.write(buffer, offset, count);
                 return;
             }
             int available = this.buf.length - pos;
@@ -197,7 +197,7 @@
                 available = count;
             }
             if (available > 0) {
-                System.arraycopy(cbuf, offset, this.buf, pos, available);
+                System.arraycopy(buffer, offset, this.buf, pos, available);
                 pos += available;
             }
             if (pos == this.buf.length) {
@@ -207,11 +207,11 @@
                     offset += available;
                     available = count - available;
                     if (available >= this.buf.length) {
-                        out.write(cbuf, offset, available);
+                        out.write(buffer, offset, available);
                         return;
                     }
 
-                    System.arraycopy(cbuf, offset, this.buf, pos, available);
+                    System.arraycopy(buffer, offset, this.buf, pos, available);
                     pos += available;
                 }
             }
diff --git a/luni/src/main/java/java/io/ByteArrayOutputStream.java b/luni/src/main/java/java/io/ByteArrayOutputStream.java
index 3ab2c20..ff9c7df 100644
--- a/luni/src/main/java/java/io/ByteArrayOutputStream.java
+++ b/luni/src/main/java/java/io/ByteArrayOutputStream.java
@@ -162,17 +162,17 @@
 
     /**
      * Returns the contents of this ByteArrayOutputStream as a string converted
-     * according to the encoding declared in {@code enc}.
+     * according to the encoding declared in {@code charsetName}.
      *
-     * @param enc
+     * @param charsetName
      *            a string representing the encoding to use when translating
      *            this stream to a string.
      * @return this stream's current contents as an encoded string.
      * @throws UnsupportedEncodingException
      *             if the provided encoding is not supported.
      */
-    public String toString(String enc) throws UnsupportedEncodingException {
-        return new String(buf, 0, count, enc);
+    public String toString(String charsetName) throws UnsupportedEncodingException {
+        return new String(buf, 0, count, charsetName);
     }
 
     /**
diff --git a/luni/src/main/java/java/io/File.java b/luni/src/main/java/java/io/File.java
index 968f021..ec87fed 100644
--- a/luni/src/main/java/java/io/File.java
+++ b/luni/src/main/java/java/io/File.java
@@ -147,7 +147,7 @@
      */
     public File(String dirPath, String name) {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
         if (dirPath == null || dirPath.isEmpty()) {
             this.path = fixSlashes(name);
@@ -855,57 +855,65 @@
     }
 
     /**
-     * Creates the directory named by the trailing filename of this file. Does
-     * not create the complete path required to create this directory.
+     * Creates the directory named by this file, assuming its parents exist.
+     * Use {@link #mkdirs} if you also want to create missing parents.
      *
      * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
-     * Callers must check the return value.
+     * Callers must check the return value. Note also that this method returns
+     * false if the directory already existed. If you want to know whether the
+     * directory exists on return, either use {@code (f.mkdir() || f.isDirectory())}
+     * or simply ignore the return value from this method and simply call {@link #isDirectory}.
      *
-     * @return {@code true} if the directory has been created, {@code false}
-     *         otherwise.
-     * @see #mkdirs
+     * @return {@code true} if the directory was created,
+     *         {@code false} on failure or if the directory already existed.
      */
     public boolean mkdir() {
         try {
-            // On Android, we don't want default permissions to allow global access.
-            Libcore.os.mkdir(path, S_IRWXU);
+            mkdirErrno();
             return true;
         } catch (ErrnoException errnoException) {
             return false;
         }
     }
 
+    private void mkdirErrno() throws ErrnoException {
+        // On Android, we don't want default permissions to allow global access.
+        Libcore.os.mkdir(path, S_IRWXU);
+    }
+
     /**
-     * Creates the directory named by the trailing filename of this file,
-     * including the complete directory path required to create this directory.
+     * Creates the directory named by this file, creating missing parent
+     * directories if necessary.
+     * Use {@link #mkdir} if you don't want to create missing parents.
      *
      * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
-     * Callers must check the return value.
+     * Callers must check the return value. Note also that this method returns
+     * false if the directory already existed. If you want to know whether the
+     * directory exists on return, either use {@code (f.mkdirs() || f.isDirectory())}
+     * or simply ignore the return value from this method and simply call {@link #isDirectory}.
      *
-     * @return {@code true} if the necessary directories have been created,
-     *         {@code false} if the target directory already exists or one of
-     *         the directories can not be created.
-     * @see #mkdir
+     * @return {@code true} if the directory was created,
+     *         {@code false} on failure or if the directory already existed.
      */
     public boolean mkdirs() {
-        /* If the terminal directory already exists, answer false */
-        if (exists()) {
-            return false;
-        }
+        return mkdirs(false);
+    }
 
-        /* If the receiver can be created, answer true */
-        if (mkdir()) {
+    private boolean mkdirs(boolean resultIfExists) {
+        try {
+            // Try to create the directory directly.
+            mkdirErrno();
             return true;
-        }
-
-        String parentDir = getParent();
-        /* If there is no parent and we were not created, answer false */
-        if (parentDir == null) {
+        } catch (ErrnoException errnoException) {
+            if (errnoException.errno == ENOENT) {
+                // If the parent was missing, try to create it and then try again.
+                File parent = getParentFile();
+                return parent != null && parent.mkdirs(true) && mkdir();
+            } else if (errnoException.errno == EEXIST) {
+                return resultIfExists;
+            }
             return false;
         }
-
-        /* Otherwise, try to create a parent directory and then this directory */
-        return (new File(parentDir).mkdirs() && mkdir());
     }
 
     /**
diff --git a/luni/src/main/java/java/io/FileDescriptor.java b/luni/src/main/java/java/io/FileDescriptor.java
index f04ae2c..e4eb06cc 100644
--- a/luni/src/main/java/java/io/FileDescriptor.java
+++ b/luni/src/main/java/java/io/FileDescriptor.java
@@ -68,7 +68,11 @@
      */
     public void sync() throws SyncFailedException {
         try {
-            Libcore.os.fsync(this);
+            if (Libcore.os.isatty(this)) {
+                Libcore.os.tcdrain(this);
+            } else {
+                Libcore.os.fsync(this);
+            }
         } catch (ErrnoException errnoException) {
             SyncFailedException sfe = new SyncFailedException(errnoException.getMessage());
             sfe.initCause(errnoException);
diff --git a/luni/src/main/java/java/io/InputStreamReader.java b/luni/src/main/java/java/io/InputStreamReader.java
index 59be9ed..d3650dc 100644
--- a/luni/src/main/java/java/io/InputStreamReader.java
+++ b/luni/src/main/java/java/io/InputStreamReader.java
@@ -62,32 +62,32 @@
     /**
      * Constructs a new InputStreamReader on the InputStream {@code in}. The
      * character converter that is used to decode bytes into characters is
-     * identified by name by {@code enc}. If the encoding cannot be found, an
+     * identified by name by {@code charsetName}. If the encoding cannot be found, an
      * UnsupportedEncodingException error is thrown.
      *
      * @param in
      *            the InputStream from which to read characters.
-     * @param enc
+     * @param charsetName
      *            identifies the character converter to use.
      * @throws NullPointerException
-     *             if {@code enc} is {@code null}.
+     *             if {@code charsetName} is {@code null}.
      * @throws UnsupportedEncodingException
-     *             if the encoding specified by {@code enc} cannot be found.
+     *             if the encoding specified by {@code charsetName} cannot be found.
      */
-    public InputStreamReader(InputStream in, final String enc)
+    public InputStreamReader(InputStream in, final String charsetName)
             throws UnsupportedEncodingException {
         super(in);
-        if (enc == null) {
-            throw new NullPointerException();
+        if (charsetName == null) {
+            throw new NullPointerException("charsetName == null");
         }
         this.in = in;
         try {
-            decoder = Charset.forName(enc).newDecoder().onMalformedInput(
+            decoder = Charset.forName(charsetName).newDecoder().onMalformedInput(
                     CodingErrorAction.REPLACE).onUnmappableCharacter(
                     CodingErrorAction.REPLACE);
         } catch (IllegalArgumentException e) {
             throw (UnsupportedEncodingException)
-                    new UnsupportedEncodingException(enc).initCause(e);
+                    new UnsupportedEncodingException(charsetName).initCause(e);
         }
         bytes.limit(0);
     }
diff --git a/luni/src/main/java/java/io/ObjectInputStream.java b/luni/src/main/java/java/io/ObjectInputStream.java
index 4541f1b..0476901 100644
--- a/luni/src/main/java/java/io/ObjectInputStream.java
+++ b/luni/src/main/java/java/io/ObjectInputStream.java
@@ -23,8 +23,8 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
-import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -1089,8 +1089,11 @@
 
         for (ObjectStreamField fieldDesc : fields) {
             Field field = classDesc.getReflectionField(fieldDesc);
-            // We may not have been able to find the field, but we still need to read the value
-            // and do the other checking, so there's no null check on 'field' here.
+            if (field != null && Modifier.isTransient(field.getModifiers())) {
+                field = null; // No setting transient fields! (http://b/4471249)
+            }
+            // We may not have been able to find the field, or it may be transient, but we still
+            // need to read the value and do the other checking...
             try {
                 Class<?> type = fieldDesc.getTypeInternal();
                 if (type == byte.class) {
@@ -2341,7 +2344,7 @@
     public int skipBytes(int length) throws IOException {
         // To be used with available. Ok to call if reading primitive buffer
         if (input == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("source stream is null");
         }
 
         int offset = 0;
diff --git a/luni/src/main/java/java/io/ObjectStreamClass.java b/luni/src/main/java/java/io/ObjectStreamClass.java
index e87fcd4..a28489a 100644
--- a/luni/src/main/java/java/io/ObjectStreamClass.java
+++ b/luni/src/main/java/java/io/ObjectStreamClass.java
@@ -481,16 +481,14 @@
                 Field field = fields[i];
                 int modifiers = field.getModifiers() & FIELD_MODIFIERS_MASK;
 
-                boolean skip = Modifier.isPrivate(modifiers)
-                        && (Modifier.isTransient(modifiers) || Modifier
-                                .isStatic(modifiers));
+                boolean skip = Modifier.isPrivate(modifiers) &&
+                        (Modifier.isTransient(modifiers) || Modifier.isStatic(modifiers));
                 if (!skip) {
                     // write name, modifier & "descriptor" of all but private
                     // static and private transient
                     output.writeUTF(field.getName());
                     output.writeInt(modifiers);
-                    output
-                            .writeUTF(descriptorForFieldSignature(getFieldSignature(field)));
+                    output.writeUTF(descriptorForFieldSignature(getFieldSignature(field)));
                 }
             }
 
diff --git a/luni/src/main/java/java/io/ObjectStreamField.java b/luni/src/main/java/java/io/ObjectStreamField.java
index db450e0..78a6903 100644
--- a/luni/src/main/java/java/io/ObjectStreamField.java
+++ b/luni/src/main/java/java/io/ObjectStreamField.java
@@ -58,8 +58,10 @@
      *             if {@code name} or {@code cl} is {@code null}.
      */
     public ObjectStreamField(String name, Class<?> cl) {
-        if (name == null || cl == null) {
-            throw new NullPointerException();
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        } else if (cl == null) {
+            throw new NullPointerException("cl == null");
         }
         this.name = name;
         this.type = new WeakReference<Class<?>>(cl);
@@ -81,8 +83,10 @@
      * @see ObjectOutputStream#writeUnshared(Object)
      */
     public ObjectStreamField(String name, Class<?> cl, boolean unshared) {
-        if (name == null || cl == null) {
-            throw new NullPointerException();
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        } else if (cl == null) {
+            throw new NullPointerException("cl == null");
         }
         this.name = name;
         this.type = (cl.getClassLoader() == null) ? cl : new WeakReference<Class<?>>(cl);
@@ -100,7 +104,7 @@
      */
     ObjectStreamField(String signature, String name) {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
         this.name = name;
         this.typeString = signature.replace('.', '/').intern();
diff --git a/luni/src/main/java/java/io/OutputStreamWriter.java b/luni/src/main/java/java/io/OutputStreamWriter.java
index 86b62fc..5dffdfe 100644
--- a/luni/src/main/java/java/io/OutputStreamWriter.java
+++ b/luni/src/main/java/java/io/OutputStreamWriter.java
@@ -57,30 +57,30 @@
 
     /**
      * Constructs a new OutputStreamWriter using {@code out} as the target
-     * stream to write converted characters to and {@code enc} as the character
+     * stream to write converted characters to and {@code charsetName} as the character
      * encoding. If the encoding cannot be found, an
      * UnsupportedEncodingException error is thrown.
      *
      * @param out
      *            the target stream to write converted bytes to.
-     * @param enc
+     * @param charsetName
      *            the string describing the desired character encoding.
      * @throws NullPointerException
-     *             if {@code enc} is {@code null}.
+     *             if {@code charsetName} is {@code null}.
      * @throws UnsupportedEncodingException
-     *             if the encoding specified by {@code enc} cannot be found.
+     *             if the encoding specified by {@code charsetName} cannot be found.
      */
-    public OutputStreamWriter(OutputStream out, final String enc)
+    public OutputStreamWriter(OutputStream out, final String charsetName)
             throws UnsupportedEncodingException {
         super(out);
-        if (enc == null) {
-            throw new NullPointerException();
+        if (charsetName == null) {
+            throw new NullPointerException("charsetName == null");
         }
         this.out = out;
         try {
-            encoder = Charset.forName(enc).newEncoder();
+            encoder = Charset.forName(charsetName).newEncoder();
         } catch (Exception e) {
-            throw new UnsupportedEncodingException(enc);
+            throw new UnsupportedEncodingException(charsetName);
         }
         encoder.onMalformedInput(CodingErrorAction.REPLACE);
         encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
@@ -106,19 +106,19 @@
 
     /**
      * Constructs a new OutputStreamWriter using {@code out} as the target
-     * stream to write converted characters to and {@code enc} as the character
+     * stream to write converted characters to and {@code charsetEncoder} as the character
      * encoder.
      *
      * @param out
      *            the target stream to write converted bytes to.
-     * @param enc
+     * @param charsetEncoder
      *            the character encoder used for character conversion.
      */
-    public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
+    public OutputStreamWriter(OutputStream out, CharsetEncoder charsetEncoder) {
         super(out);
-        enc.charset();
+        charsetEncoder.charset();
         this.out = out;
-        encoder = enc;
+        encoder = charsetEncoder;
     }
 
     /**
diff --git a/luni/src/main/java/java/io/PipedOutputStream.java b/luni/src/main/java/java/io/PipedOutputStream.java
index a674bb3..1b139e9 100644
--- a/luni/src/main/java/java/io/PipedOutputStream.java
+++ b/luni/src/main/java/java/io/PipedOutputStream.java
@@ -81,7 +81,7 @@
      */
     public void connect(PipedInputStream stream) throws IOException {
         if (stream == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("stream == null");
         }
         synchronized (stream) {
             if (this.target != null) {
diff --git a/luni/src/main/java/java/io/PipedWriter.java b/luni/src/main/java/java/io/PipedWriter.java
index ece899a..ad8974b 100644
--- a/luni/src/main/java/java/io/PipedWriter.java
+++ b/luni/src/main/java/java/io/PipedWriter.java
@@ -85,7 +85,7 @@
      */
     public void connect(PipedReader reader) throws IOException {
         if (reader == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("reader == null");
         }
         synchronized (reader) {
             if (this.destination != null) {
diff --git a/luni/src/main/java/java/io/PrintStream.java b/luni/src/main/java/java/io/PrintStream.java
index ba48b04..18f2310 100644
--- a/luni/src/main/java/java/io/PrintStream.java
+++ b/luni/src/main/java/java/io/PrintStream.java
@@ -59,7 +59,7 @@
     public PrintStream(OutputStream out) {
         super(out);
         if (out == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("out == null");
         }
     }
 
@@ -80,14 +80,14 @@
     public PrintStream(OutputStream out, boolean autoFlush) {
         super(out);
         if (out == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("out == null");
         }
         this.autoFlush = autoFlush;
     }
 
     /**
      * Constructs a new {@code PrintStream} with {@code out} as its target
-     * stream and using the character encoding {@code enc} while writing. The
+     * stream and using the character encoding {@code charsetName} while writing. The
      * parameter {@code autoFlush} determines if the print stream automatically
      * flushes its contents to the target stream when a newline is encountered.
      *
@@ -96,28 +96,30 @@
      * @param autoFlush
      *            indicates whether or not to flush contents upon encountering a
      *            newline sequence.
-     * @param enc
+     * @param charsetName
      *            the non-null string describing the desired character encoding.
      * @throws NullPointerException
-     *             if {@code out} or {@code enc} are {@code null}.
+     *             if {@code out} or {@code charsetName} are {@code null}.
      * @throws UnsupportedEncodingException
-     *             if the encoding specified by {@code enc} is not supported.
+     *             if the encoding specified by {@code charsetName} is not supported.
      */
-    public PrintStream(OutputStream out, boolean autoFlush, String enc)
+    public PrintStream(OutputStream out, boolean autoFlush, String charsetName)
             throws UnsupportedEncodingException {
         super(out);
-        if (out == null || enc == null) {
-            throw new NullPointerException();
+        if (out == null) {
+            throw new NullPointerException("out == null");
+        } else if (charsetName == null) {
+            throw new NullPointerException("charsetName == null");
         }
         this.autoFlush = autoFlush;
         try {
-            if (!Charset.isSupported(enc)) {
-                throw new UnsupportedEncodingException(enc);
+            if (!Charset.isSupported(charsetName)) {
+                throw new UnsupportedEncodingException(charsetName);
             }
         } catch (IllegalCharsetNameException e) {
-            throw new UnsupportedEncodingException(enc);
+            throw new UnsupportedEncodingException(charsetName);
         }
-        encoding = enc;
+        encoding = charsetName;
     }
 
     /**
@@ -136,30 +138,30 @@
 
     /**
      * Constructs a new {@code PrintStream} with {@code file} as its target. The
-     * character set named {@code csn} is used for character encoding.
+     * character set named {@code charsetName} is used for character encoding.
      *
      * @param file
      *            the target file. If the file already exists, its contents are
      *            removed, otherwise a new file is created.
-     * @param csn
+     * @param charsetName
      *            the name of the character set used for character encoding.
      * @throws FileNotFoundException
      *             if an error occurs while opening or creating the target file.
      * @throws NullPointerException
-     *             if {@code csn} is {@code null}.
+     *             if {@code charsetName} is {@code null}.
      * @throws UnsupportedEncodingException
-     *             if the encoding specified by {@code csn} is not supported.
+     *             if the encoding specified by {@code charsetName} is not supported.
      */
-    public PrintStream(File file, String csn) throws FileNotFoundException,
+    public PrintStream(File file, String charsetName) throws FileNotFoundException,
             UnsupportedEncodingException {
         super(new FileOutputStream(file));
-        if (csn == null) {
-            throw new NullPointerException();
+        if (charsetName == null) {
+            throw new NullPointerException("charsetName == null");
         }
-        if (!Charset.isSupported(csn)) {
-            throw new UnsupportedEncodingException(csn);
+        if (!Charset.isSupported(charsetName)) {
+            throw new UnsupportedEncodingException(charsetName);
         }
-        encoding = csn;
+        encoding = charsetName;
     }
 
     /**
@@ -179,24 +181,24 @@
 
     /**
      * Constructs a new {@code PrintStream} with the file identified by
-     * {@code fileName} as its target. The character set named {@code csn} is
+     * {@code fileName} as its target. The character set named {@code charsetName} is
      * used for character encoding.
      *
      * @param fileName
      *            the target file's name. If the file already exists, its
      *            contents are removed, otherwise a new file is created.
-     * @param csn
+     * @param charsetName
      *            the name of the character set used for character encoding.
      * @throws FileNotFoundException
      *             if an error occurs while opening or creating the target file.
      * @throws NullPointerException
-     *             if {@code csn} is {@code null}.
+     *             if {@code charsetName} is {@code null}.
      * @throws UnsupportedEncodingException
-     *             if the encoding specified by {@code csn} is not supported.
+     *             if the encoding specified by {@code charsetName} is not supported.
      */
-    public PrintStream(String fileName, String csn)
+    public PrintStream(String fileName, String charsetName)
             throws FileNotFoundException, UnsupportedEncodingException {
-        this(new File(fileName), csn);
+        this(new File(fileName), charsetName);
     }
 
     /**
diff --git a/luni/src/main/java/java/io/Reader.java b/luni/src/main/java/java/io/Reader.java
index 310a57c..e947d08 100644
--- a/luni/src/main/java/java/io/Reader.java
+++ b/luni/src/main/java/java/io/Reader.java
@@ -61,7 +61,7 @@
      */
     protected Reader(Object lock) {
         if (lock == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("lock == null");
         }
         this.lock = lock;
     }
diff --git a/luni/src/main/java/java/io/SequenceInputStream.java b/luni/src/main/java/java/io/SequenceInputStream.java
index 9ae1901..8333834 100644
--- a/luni/src/main/java/java/io/SequenceInputStream.java
+++ b/luni/src/main/java/java/io/SequenceInputStream.java
@@ -50,7 +50,7 @@
      */
     public SequenceInputStream(InputStream s1, InputStream s2) {
         if (s1 == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("s1 == null");
         }
         Vector<InputStream> inVector = new Vector<InputStream>(1);
         inVector.addElement(s2);
@@ -73,7 +73,7 @@
         if (e.hasMoreElements()) {
             in = e.nextElement();
             if (in == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("element is null");
             }
         }
     }
@@ -112,7 +112,7 @@
         if (e.hasMoreElements()) {
             in = e.nextElement();
             if (in == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("element is null");
             }
         } else {
             in = null;
diff --git a/luni/src/main/java/java/io/StreamTokenizer.java b/luni/src/main/java/java/io/StreamTokenizer.java
index 0522be6..a16dc4b 100644
--- a/luni/src/main/java/java/io/StreamTokenizer.java
+++ b/luni/src/main/java/java/io/StreamTokenizer.java
@@ -167,7 +167,7 @@
     public StreamTokenizer(InputStream is) {
         this();
         if (is == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("is == null");
         }
         inStream = is;
     }
@@ -194,7 +194,7 @@
     public StreamTokenizer(Reader r) {
         this();
         if (r == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("r == null");
         }
         inReader = r;
     }
diff --git a/luni/src/main/java/java/io/StringBufferInputStream.java b/luni/src/main/java/java/io/StringBufferInputStream.java
index 1fada57..1768abe 100644
--- a/luni/src/main/java/java/io/StringBufferInputStream.java
+++ b/luni/src/main/java/java/io/StringBufferInputStream.java
@@ -54,7 +54,7 @@
      */
     public StringBufferInputStream(String str) {
         if (str == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("str == null");
         }
         buffer = str;
         count = str.length();
diff --git a/luni/src/main/java/java/io/Writer.java b/luni/src/main/java/java/io/Writer.java
index 2e28b80..33d7604 100644
--- a/luni/src/main/java/java/io/Writer.java
+++ b/luni/src/main/java/java/io/Writer.java
@@ -59,7 +59,7 @@
      */
     protected Writer(Object lock) {
         if (lock == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("lock == null");
         }
         this.lock = lock;
     }
diff --git a/luni/src/main/java/java/lang/AbstractStringBuilder.java b/luni/src/main/java/java/lang/AbstractStringBuilder.java
index baab47d..c3107f2 100644
--- a/luni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/luni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -77,7 +77,7 @@
 
     AbstractStringBuilder(int capacity) {
         if (capacity < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(capacity));
         }
         value = new char[capacity];
     }
@@ -437,7 +437,7 @@
             }
             if (start == end) {
                 if (string == null) {
-                    throw new NullPointerException();
+                    throw new NullPointerException("string == null");
                 }
                 insert0(start, string);
                 return;
diff --git a/luni/src/main/java/java/lang/Character.java b/luni/src/main/java/java/lang/Character.java
index 1a41ec2..cf0ab84 100644
--- a/luni/src/main/java/java/lang/Character.java
+++ b/luni/src/main/java/java/lang/Character.java
@@ -532,7 +532,7 @@
          */
         protected Subset(String string) {
             if (string == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("string == null");
             }
             name = string;
         }
@@ -1502,7 +1502,7 @@
          */
         public static UnicodeBlock forName(String blockName) {
             if (blockName == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("blockName == null");
             }
             int block = forNameImpl(blockName);
             if (block == -1) {
@@ -1798,7 +1798,7 @@
      */
     public static int codePointAt(CharSequence seq, int index) {
         if (seq == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("seq == null");
         }
         int len = seq.length();
         if (index < 0 || index >= len) {
@@ -1840,7 +1840,7 @@
      */
     public static int codePointAt(char[] seq, int index) {
         if (seq == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("seq == null");
         }
         int len = seq.length;
         if (index < 0 || index >= len) {
@@ -1923,7 +1923,7 @@
      */
     public static int codePointBefore(CharSequence seq, int index) {
         if (seq == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("seq == null");
         }
         int len = seq.length();
         if (index < 1 || index > len) {
@@ -1965,7 +1965,7 @@
      */
     public static int codePointBefore(char[] seq, int index) {
         if (seq == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("seq == null");
         }
         int len = seq.length;
         if (index < 1 || index > len) {
@@ -2012,7 +2012,7 @@
      */
     public static int codePointBefore(char[] seq, int index, int start) {
         if (seq == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("seq == null");
         }
         int len = seq.length;
         if (index <= start || index > len || start < 0 || start >= len) {
@@ -2055,7 +2055,7 @@
     public static int toChars(int codePoint, char[] dst, int dstIndex) {
         checkValidCodePoint(codePoint);
         if (dst == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("dst == null");
         }
         if (dstIndex < 0 || dstIndex >= dst.length) {
             throw new IndexOutOfBoundsException();
@@ -2126,7 +2126,7 @@
     public static int codePointCount(CharSequence seq, int beginIndex,
             int endIndex) {
         if (seq == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("seq == null");
         }
         int len = seq.length();
         if (beginIndex < 0 || endIndex > len || beginIndex > endIndex) {
@@ -2215,7 +2215,7 @@
      */
     public static int offsetByCodePoints(CharSequence seq, int index, int codePointOffset) {
         if (seq == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("seq == null");
         }
         int len = seq.length();
         if (index < 0 || index > len) {
diff --git a/luni/src/main/java/java/lang/ClassLoader.java b/luni/src/main/java/java/lang/ClassLoader.java
index 0cdc448..c99d57c 100644
--- a/luni/src/main/java/java/lang/ClassLoader.java
+++ b/luni/src/main/java/java/lang/ClassLoader.java
@@ -195,7 +195,7 @@
      */
     ClassLoader(ClassLoader parentLoader, boolean nullAllowed) {
         if (parentLoader == null && !nullAllowed) {
-            throw new NullPointerException("Parent ClassLoader may not be null");
+            throw new NullPointerException("parentLoader == null && !nullAllowed");
         }
         parent = parentLoader;
     }
diff --git a/luni/src/main/java/java/lang/Daemons.java b/luni/src/main/java/java/lang/Daemons.java
index a7d0964..78a4152 100644
--- a/luni/src/main/java/java/lang/Daemons.java
+++ b/luni/src/main/java/java/lang/Daemons.java
@@ -31,8 +31,9 @@
  * @hide
  */
 public final class Daemons {
-    private static final int NANOS_PER_MILLI = 1000000;
-    private static final long MAX_FINALIZE_MILLIS = 10L * 1000L; // 10 seconds
+    private static final int NANOS_PER_MILLI = 1000 * 1000;
+    private static final int NANOS_PER_SECOND = NANOS_PER_MILLI * 1000;
+    private static final long MAX_FINALIZE_NANOS = 10L * NANOS_PER_SECOND;
 
     public static void start() {
         ReferenceQueueDaemon.INSTANCE.start();
@@ -203,41 +204,78 @@
 
         @Override public void run() {
             while (isRunning()) {
-                try {
-                    Object object = FinalizerDaemon.INSTANCE.finalizingObject;
-                    long startedNanos = FinalizerDaemon.INSTANCE.finalizingStartedNanos;
-
-                    if (object == null) {
-                        synchronized (this) {
-                            // wait until something is being finalized
-                            // http://code.google.com/p/android/issues/detail?id=22778
-                            wait();
-                            continue;
-                        }
-                    }
-
-                    long elapsedMillis = (System.nanoTime() - startedNanos) / NANOS_PER_MILLI;
-                    long sleepMillis = MAX_FINALIZE_MILLIS - elapsedMillis;
-                    if (sleepMillis > 0) {
-                        Thread.sleep(sleepMillis);
-                        elapsedMillis = (System.nanoTime() - startedNanos) / NANOS_PER_MILLI;
-                    }
-
-                    if (object != FinalizerDaemon.INSTANCE.finalizingObject
-                            || VMRuntime.getRuntime().isDebuggerActive()) {
-                        continue;
-                    }
-
-                    // The current object has exceeded the finalization deadline; abort!
-                    Exception syntheticException = new TimeoutException();
-                    syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
-                    System.logE(object.getClass().getName() + ".finalize() timed out after "
-                            + elapsedMillis + " ms; limit is " + MAX_FINALIZE_MILLIS + " ms",
-                            syntheticException);
-                    System.exit(2);
-                } catch (InterruptedException ignored) {
+                Object object = waitForObject();
+                if (object == null) {
+                    // We have been interrupted, need to see if this daemon has been stopped.
+                    continue;
+                }
+                boolean finalized = waitForFinalization(object);
+                if (!finalized && !VMRuntime.getRuntime().isDebuggerActive()) {
+                    finalizerTimedOut(object);
+                    break;
                 }
             }
         }
+
+        private Object waitForObject() {
+            while (true) {
+                Object object = FinalizerDaemon.INSTANCE.finalizingObject;
+                if (object != null) {
+                    return object;
+                }
+                synchronized (this) {
+                    // wait until something is ready to be finalized
+                    // http://code.google.com/p/android/issues/detail?id=22778
+                    try {
+                        wait();
+                    } catch (InterruptedException e) {
+                        // Daemon.stop may have interrupted us.
+                        return null;
+                    }
+                }
+            }
+        }
+
+        private void sleepFor(long startNanos, long durationNanos) {
+            while (true) {
+                long elapsedNanos = System.nanoTime() - startNanos;
+                long sleepNanos = durationNanos - elapsedNanos;
+                long sleepMills = sleepNanos / NANOS_PER_MILLI;
+                if (sleepMills <= 0) {
+                    return;
+                }
+                try {
+                    Thread.sleep(sleepMills);
+                } catch (InterruptedException e) {
+                    if (!isRunning()) {
+                        return;
+                    }
+                }
+            }
+        }
+
+        private boolean waitForFinalization(Object object) {
+            sleepFor(FinalizerDaemon.INSTANCE.finalizingStartedNanos, MAX_FINALIZE_NANOS);
+            return object != FinalizerDaemon.INSTANCE.finalizingObject;
+        }
+
+        private static void finalizerTimedOut(Object object) {
+            // The current object has exceeded the finalization deadline; abort!
+            String message = object.getClass().getName() + ".finalize() timed out after "
+                    + (MAX_FINALIZE_NANOS / NANOS_PER_SECOND) + " seconds";
+            Exception syntheticException = new TimeoutException(message);
+            // We use the stack from where finalize() was running to show where it was stuck.
+            syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
+            Thread.UncaughtExceptionHandler h = Thread.getDefaultUncaughtExceptionHandler();
+            if (h == null) {
+                // If we have no handler, log and exit.
+                System.logE(message, syntheticException);
+                System.exit(2);
+            }
+            // Otherwise call the handler to do crash reporting.
+            // We don't just throw because we're not the thread that
+            // timed out; we're the thread that detected it.
+            h.uncaughtException(Thread.currentThread(), syntheticException);
+        }
     }
 }
diff --git a/luni/src/main/java/java/lang/Enum.java b/luni/src/main/java/java/lang/Enum.java
index 391670c..7a0f514 100644
--- a/luni/src/main/java/java/lang/Enum.java
+++ b/luni/src/main/java/java/lang/Enum.java
@@ -34,6 +34,9 @@
     private static final BasicLruCache<Class<? extends Enum>, Object[]> sharedConstantsCache
             = new BasicLruCache<Class<? extends Enum>, Object[]>(64) {
         @Override protected Object[] create(Class<? extends Enum> enumType) {
+            if (!enumType.isEnum()) {
+                return null;
+            }
             Method method = (Method) Class.getDeclaredConstructorOrMethod(
                     enumType, "values", EmptyArray.CLASS);
             try {
@@ -178,13 +181,16 @@
      *             have a constant value called {@code name}.
      */
     public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {
-        if (enumType == null || name == null) {
-            throw new NullPointerException("enumType == null || name == null");
+        if (enumType == null) {
+            throw new NullPointerException("enumType == null");
+        } else if (name == null) {
+            throw new NullPointerException("name == null");
         }
-        if (!enumType.isEnum()) {
+        T[] values = getSharedConstants(enumType);
+        if (values == null) {
             throw new IllegalArgumentException(enumType + " is not an enum type");
         }
-        for (T value : getSharedConstants(enumType)) {
+        for (T value : values) {
             if (name.equals(value.name())) {
                 return value;
             }
diff --git a/luni/src/main/java/java/lang/Math.java b/luni/src/main/java/java/lang/Math.java
index 68db4fa..22c89ce 100644
--- a/luni/src/main/java/java/lang/Math.java
+++ b/luni/src/main/java/java/lang/Math.java
@@ -53,10 +53,6 @@
      * <li>{@code abs(-infinity) = +infinity}</li>
      * <li>{@code abs(NaN) = NaN}</li>
      * </ul>
-     *
-     * @param d
-     *            the value whose absolute value has to be computed.
-     * @return the absolute value of the argument.
      */
     public static native double abs(double d);
 
@@ -70,11 +66,6 @@
      * <li>{@code abs(-infinity) = +infinity}</li>
      * <li>{@code abs(NaN) = NaN}</li>
      * </ul>
-     *
-     * @param f
-     *            the value whose absolute value has to be computed.
-     * @return the argument if it is positive, otherwise the negation of the
-     *         argument.
      */
     public static native float abs(float f);
 
@@ -83,22 +74,12 @@
      * <p>
      * If the argument is {@code Integer.MIN_VALUE}, {@code Integer.MIN_VALUE}
      * is returned.
-     *
-     * @param i
-     *            the value whose absolute value has to be computed.
-     * @return the argument if it is positive, otherwise the negation of the
-     *         argument.
      */
     public static native int abs(int i);
 
     /**
      * Returns the absolute value of the argument. If the argument is {@code
      * Long.MIN_VALUE}, {@code Long.MIN_VALUE} is returned.
-     *
-     * @param l
-     *            the value whose absolute value has to be computed.
-     * @return the argument if it is positive, otherwise the negation of the
-     *         argument.
      */
     public static native long abs(long l);
 
@@ -467,12 +448,6 @@
      * <li>{@code max(+0.0, -0.0) = +0.0}</li>
      * <li>{@code max(-0.0, +0.0) = +0.0}</li>
      * </ul>
-     *
-     * @param d1
-     *            the first argument.
-     * @param d2
-     *            the second argument.
-     * @return the larger of {@code d1} and {@code d2}.
      */
     public static double max(double d1, double d2) {
         if (d1 > d2) {
@@ -504,12 +479,6 @@
      * <li>{@code max(+0.0, -0.0) = +0.0}</li>
      * <li>{@code max(-0.0, +0.0) = +0.0}</li>
      * </ul>
-     *
-     * @param f1
-     *            the first argument.
-     * @param f2
-     *            the second argument.
-     * @return the larger of {@code f1} and {@code f2}.
      */
     public static float max(float f1, float f2) {
         if (f1 > f2) {
@@ -533,24 +502,12 @@
     /**
      * Returns the most positive (closest to positive infinity) of the two
      * arguments.
-     *
-     * @param i1
-     *            the first argument.
-     * @param i2
-     *            the second argument.
-     * @return the larger of {@code i1} and {@code i2}.
      */
     public static native int max(int i1, int i2);
 
     /**
      * Returns the most positive (closest to positive infinity) of the two
      * arguments.
-     *
-     * @param l1
-     *            the first argument.
-     * @param l2
-     *            the second argument.
-     * @return the larger of {@code l1} and {@code l2}.
      */
     public static long max(long l1, long l2) {
         return l1 > l2 ? l1 : l2;
@@ -567,12 +524,6 @@
      * <li>{@code min(+0.0, -0.0) = -0.0}</li>
      * <li>{@code min(-0.0, +0.0) = -0.0}</li>
      * </ul>
-     *
-     * @param d1
-     *            the first argument.
-     * @param d2
-     *            the second argument.
-     * @return the smaller of {@code d1} and {@code d2}.
      */
     public static double min(double d1, double d2) {
         if (d1 > d2) {
@@ -604,12 +555,6 @@
      * <li>{@code min(+0.0, -0.0) = -0.0}</li>
      * <li>{@code min(-0.0, +0.0) = -0.0}</li>
      * </ul>
-     *
-     * @param f1
-     *            the first argument.
-     * @param f2
-     *            the second argument.
-     * @return the smaller of {@code f1} and {@code f2}.
      */
     public static float min(float f1, float f2) {
         if (f1 > f2) {
@@ -633,24 +578,12 @@
     /**
      * Returns the most negative (closest to negative infinity) of the two
      * arguments.
-     *
-     * @param i1
-     *            the first argument.
-     * @param i2
-     *            the second argument.
-     * @return the smaller of {@code i1} and {@code i2}.
      */
     public static native int min(int i1, int i2);
 
     /**
      * Returns the most negative (closest to negative infinity) of the two
      * arguments.
-     *
-     * @param l1
-     *            the first argument.
-     * @param l2
-     *            the second argument.
-     * @return the smaller of {@code l1} and {@code l2}.
      */
     public static long min(long l1, long l2) {
         return l1 < l2 ? l1 : l2;
@@ -884,10 +817,6 @@
      * <li>{@code sqrt(+infinity) = +infinity}</li>
      * <li>{@code sqrt(NaN) = NaN}</li>
      * </ul>
-     *
-     * @param d
-     *            the value whose square root has to be computed.
-     * @return the square root of the argument.
      */
     public static native double sqrt(double d);
 
diff --git a/luni/src/main/java/java/lang/ProcessBuilder.java b/luni/src/main/java/java/lang/ProcessBuilder.java
index 5b7efdc..57e21b6 100644
--- a/luni/src/main/java/java/lang/ProcessBuilder.java
+++ b/luni/src/main/java/java/lang/ProcessBuilder.java
@@ -59,7 +59,7 @@
      */
     public ProcessBuilder(List<String> command) {
         if (command == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("command == null");
         }
         this.command = command;
 
@@ -102,7 +102,7 @@
      */
     public ProcessBuilder command(List<String> command) {
         if (command == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("command == null");
         }
         this.command = command;
         return this;
diff --git a/luni/src/main/java/java/lang/ProcessManager.java b/luni/src/main/java/java/lang/ProcessManager.java
index 1e820a9..28314b7 100644
--- a/luni/src/main/java/java/lang/ProcessManager.java
+++ b/luni/src/main/java/java/lang/ProcessManager.java
@@ -168,10 +168,10 @@
             boolean redirectErrorStream) throws IOException {
         // Make sure we throw the same exceptions as the RI.
         if (taintedCommand == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("taintedCommand == null");
         }
         if (taintedCommand.length == 0) {
-            throw new IndexOutOfBoundsException();
+            throw new IndexOutOfBoundsException("taintedCommand.length == 0");
         }
 
         // Handle security and safety by copying mutable inputs and checking them.
@@ -179,16 +179,16 @@
         String[] environment = taintedEnvironment != null ? taintedEnvironment.clone() : null;
 
         // Check we're not passing null Strings to the native exec.
-        for (String arg : command) {
-            if (arg == null) {
-                throw new NullPointerException();
+        for (int i = 0; i < command.length; i++) {
+            if (command[i] == null) {
+                throw new NullPointerException("taintedCommand[" + i + "] == null");
             }
         }
         // The environment is allowed to be null or empty, but no element may be null.
         if (environment != null) {
-            for (String env : environment) {
-                if (env == null) {
-                    throw new NullPointerException();
+            for (int i = 0; i < environment.length; i++) {
+                if (environment[i] == null) {
+                    throw new NullPointerException("taintedEnvironment[" + i + "] == null");
                 }
             }
         }
diff --git a/luni/src/main/java/java/lang/Runtime.java b/luni/src/main/java/java/lang/Runtime.java
index 320f157..a2debfd 100644
--- a/luni/src/main/java/java/lang/Runtime.java
+++ b/luni/src/main/java/java/lang/Runtime.java
@@ -224,9 +224,9 @@
     public Process exec(String prog, String[] envp, File directory) throws java.io.IOException {
         // Sanity checks
         if (prog == null) {
-            throw new NullPointerException();
-        } else if (prog.length() == 0) {
-            throw new IllegalArgumentException();
+            throw new NullPointerException("prog == null");
+        } else if (prog.isEmpty()) {
+            throw new IllegalArgumentException("prog is empty");
         }
 
         // Break down into tokens, as described in Java docs
@@ -331,11 +331,11 @@
     /*
      * Loads and links a library without security checks.
      */
-    void load(String filename, ClassLoader loader) {
-        if (filename == null) {
-            throw new NullPointerException("library path was null.");
+    void load(String pathName, ClassLoader loader) {
+        if (pathName == null) {
+            throw new NullPointerException("pathName == null");
         }
-        String error = nativeLoad(filename, loader);
+        String error = nativeLoad(pathName, loader);
         if (error != null) {
             throw new UnsatisfiedLinkError(error);
         }
@@ -362,8 +362,9 @@
         if (loader != null) {
             String filename = loader.findLibrary(libraryName);
             if (filename == null) {
-                throw new UnsatisfiedLinkError("Couldn't load " + libraryName + ": " +
-                        "findLibrary returned null");
+                throw new UnsatisfiedLinkError("Couldn't load " + libraryName
+                                               + " from loader " + loader
+                                               + ": findLibrary returned null");
             }
             String error = nativeLoad(filename, loader);
             if (error != null) {
@@ -537,7 +538,7 @@
     public void addShutdownHook(Thread hook) {
         // Sanity checks
         if (hook == null) {
-            throw new NullPointerException("Hook may not be null.");
+            throw new NullPointerException("hook == null");
         }
 
         if (shuttingDown) {
@@ -570,7 +571,7 @@
     public boolean removeShutdownHook(Thread hook) {
         // Sanity checks
         if (hook == null) {
-            throw new NullPointerException("Hook may not be null.");
+            throw new NullPointerException("hook == null");
         }
 
         if (shuttingDown) {
diff --git a/luni/src/main/java/java/lang/StackTraceElement.java b/luni/src/main/java/java/lang/StackTraceElement.java
index b83120c..a59935a 100644
--- a/luni/src/main/java/java/lang/StackTraceElement.java
+++ b/luni/src/main/java/java/lang/StackTraceElement.java
@@ -58,8 +58,10 @@
      *             if {@code cls} or {@code method} is {@code null}.
      */
     public StackTraceElement(String cls, String method, String file, int line) {
-        if (cls == null || method == null) {
-            throw new NullPointerException();
+        if (cls == null) {
+            throw new NullPointerException("cls == null");
+        } else if (method == null) {
+            throw new NullPointerException("method == null");
         }
         declaringClass = cls;
         methodName = method;
diff --git a/luni/src/main/java/java/lang/StrictMath.java b/luni/src/main/java/java/lang/StrictMath.java
index d21027b..6571b2d 100644
--- a/luni/src/main/java/java/lang/StrictMath.java
+++ b/luni/src/main/java/java/lang/StrictMath.java
@@ -62,10 +62,6 @@
      * <li>{@code abs(-infinity) = +infinity}</li>
      * <li>{@code abs(NaN) = NaN}</li>
      * </ul>
-     *
-     * @param d
-     *            the value whose absolute value has to be computed.
-     * @return the absolute value of the argument.
      */
     public static double abs(double d) {
         return Math.abs(d);
@@ -81,11 +77,6 @@
      * <li>{@code abs(-infinity) = +infinity}</li>
      * <li>{@code abs(NaN) = NaN}</li>
      * </ul>
-     *
-     * @param f
-     *            the value whose absolute value has to be computed.
-     * @return the argument if it is positive, otherwise the negation of the
-     *         argument.
      */
     public static float abs(float f) {
         return Math.abs(f);
@@ -96,11 +87,6 @@
      * <p>
      * If the argument is {@code Integer.MIN_VALUE}, {@code Integer.MIN_VALUE}
      * is returned.
-     *
-     * @param i
-     *            the value whose absolute value has to be computed.
-     * @return the argument if it is positive, otherwise the negation of the
-     *         argument.
      */
     public static int abs(int i) {
         return Math.abs(i);
@@ -111,11 +97,6 @@
      * <p>
      * If the argument is {@code Long.MIN_VALUE}, {@code Long.MIN_VALUE} is
      * returned.
-     *
-     * @param l
-     *            the value whose absolute value has to be computed.
-     * @return the argument if it is positive, otherwise the negation of the
-     *         argument.
      */
     public static long abs(long l) {
         return Math.abs(l);
@@ -469,12 +450,6 @@
      * <li>{@code max(+0.0, -0.0) = +0.0}</li>
      * <li>{@code max(-0.0, +0.0) = +0.0}</li>
      * </ul>
-     *
-     * @param d1
-     *            the first argument.
-     * @param d2
-     *            the second argument.
-     * @return the larger of {@code d1} and {@code d2}.
      */
     public static double max(double d1, double d2) {
         if (d1 > d2)
@@ -502,12 +477,6 @@
      * <li>{@code max(+0.0, -0.0) = +0.0}</li>
      * <li>{@code max(-0.0, +0.0) = +0.0}</li>
      * </ul>
-     *
-     * @param f1
-     *            the first argument.
-     * @param f2
-     *            the second argument.
-     * @return the larger of {@code f1} and {@code f2}.
      */
     public static float max(float f1, float f2) {
         if (f1 > f2)
@@ -527,12 +496,6 @@
     /**
      * Returns the most positive (closest to positive infinity) of the two
      * arguments.
-     *
-     * @param i1
-     *            the first argument.
-     * @param i2
-     *            the second argument.
-     * @return the larger of {@code i1} and {@code i2}.
      */
     public static int max(int i1, int i2) {
         return Math.max(i1, i2);
@@ -541,15 +504,9 @@
     /**
      * Returns the most positive (closest to positive infinity) of the two
      * arguments.
-     *
-     * @param l1
-     *            the first argument.
-     * @param l2
-     *            the second argument.
-     * @return the larger of {@code l1} and {@code l2}.
      */
     public static long max(long l1, long l2) {
-        return Math.max(l1, l2);
+        return l1 > l2 ? l1 : l2;
     }
 
     /**
@@ -563,12 +520,6 @@
      * <li>{@code min(+0.0, -0.0) = -0.0}</li>
      * <li>{@code min(-0.0, +0.0) = -0.0}</li>
      * </ul>
-     *
-     * @param d1
-     *            the first argument.
-     * @param d2
-     *            the second argument.
-     * @return the smaller of {@code d1} and {@code d2}.
      */
     public static double min(double d1, double d2) {
         if (d1 > d2)
@@ -596,12 +547,6 @@
      * <li>{@code min(+0.0, -0.0) = -0.0}</li>
      * <li>{@code min(-0.0, +0.0) = -0.0}</li>
      * </ul>
-     *
-     * @param f1
-     *            the first argument.
-     * @param f2
-     *            the second argument.
-     * @return the smaller of {@code f1} and {@code f2}.
      */
     public static float min(float f1, float f2) {
         if (f1 > f2)
@@ -621,12 +566,6 @@
     /**
      * Returns the most negative (closest to negative infinity) of the two
      * arguments.
-     *
-     * @param i1
-     *            the first argument.
-     * @param i2
-     *            the second argument.
-     * @return the smaller of {@code i1} and {@code i2}.
      */
     public static int min(int i1, int i2) {
         return Math.min(i1, i2);
@@ -635,15 +574,9 @@
     /**
      * Returns the most negative (closest to negative infinity) of the two
      * arguments.
-     *
-     * @param l1
-     *            the first argument.
-     * @param l2
-     *            the second argument.
-     * @return the smaller of {@code l1} and {@code l2}.
      */
     public static long min(long l1, long l2) {
-        return Math.min(l1, l2);
+        return l1 < l2 ? l1 : l2;
     }
 
     /**
@@ -856,10 +789,6 @@
      * <li>{@code sqrt(+infinity) = +infinity}</li>
      * <li>{@code sqrt(NaN) = NaN}</li>
      * </ul>
-     *
-     * @param d
-     *            the value whose square root has to be computed.
-     * @return the square root of the argument.
      */
     public static native double sqrt(double d);
 
diff --git a/luni/src/main/java/java/lang/String.java b/luni/src/main/java/java/lang/String.java
index efd4210..f3aeb64 100644
--- a/luni/src/main/java/java/lang/String.java
+++ b/luni/src/main/java/java/lang/String.java
@@ -168,17 +168,7 @@
      *             if {@code byteCount < 0 || offset < 0 || offset + byteCount > data.length}.
      */
     public String(byte[] data, int offset, int byteCount) {
-        if ((offset | byteCount) < 0 || byteCount > data.length - offset) {
-            throw failedBoundsCheck(data.length, offset, byteCount);
-        }
-        CharBuffer cb = Charset.defaultCharset().decode(ByteBuffer.wrap(data, offset, byteCount));
-        this.count = cb.length();
-        this.offset = 0;
-        if (count > 0) {
-            value = cb.array();
-        } else {
-            value = EmptyArray.CHAR;
-        }
+        this(data, offset, byteCount, Charset.defaultCharset());
     }
 
     /**
@@ -524,7 +514,7 @@
      */
     public String(int[] codePoints, int offset, int count) {
         if (codePoints == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("codePoints == null");
         }
         if ((offset | count) < 0 || count > codePoints.length - offset) {
             throw failedBoundsCheck(codePoints.length, offset, count);
@@ -1232,7 +1222,7 @@
      */
     public boolean regionMatches(int thisStart, String string, int start, int length) {
         if (string == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("string == null");
         }
         if (start < 0 || string.count - start < length) {
             return false;
@@ -1729,7 +1719,7 @@
      */
     public boolean contentEquals(CharSequence cs) {
         if (cs == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("cs == null");
         }
 
         int len = cs.length();
@@ -1922,7 +1912,7 @@
      */
     public boolean contains(CharSequence cs) {
         if (cs == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("cs == null");
         }
         return indexOf(cs.toString()) >= 0;
     }
@@ -1991,7 +1981,7 @@
      */
     public static String format(Locale locale, String format, Object... args) {
         if (format == null) {
-            throw new NullPointerException("null format argument");
+            throw new NullPointerException("format == null");
         }
         int bufferSize = format.length() + (args == null ? 0 : args.length * 10);
         Formatter f = new Formatter(new StringBuilder(bufferSize), locale);
diff --git a/luni/src/main/java/java/lang/StringBuilder.java b/luni/src/main/java/java/lang/StringBuilder.java
index d886100..a944e68 100644
--- a/luni/src/main/java/java/lang/StringBuilder.java
+++ b/luni/src/main/java/java/lang/StringBuilder.java
@@ -624,7 +624,7 @@
      *            the inclusive begin index.
      * @param end
      *            the exclusive end index.
-     * @param str
+     * @param string
      *            the replacement string.
      * @return this builder.
      * @throws StringIndexOutOfBoundsException
@@ -633,8 +633,8 @@
      * @throws NullPointerException
      *            if {@code str} is {@code null}.
      */
-    public StringBuilder replace(int start, int end, String str) {
-        replace0(start, end, str);
+    public StringBuilder replace(int start, int end, String string) {
+        replace0(start, end, string);
         return this;
     }
 
diff --git a/luni/src/main/java/java/lang/System.java b/luni/src/main/java/java/lang/System.java
index 24ebf6b..df84c61 100644
--- a/luni/src/main/java/java/lang/System.java
+++ b/luni/src/main/java/java/lang/System.java
@@ -34,6 +34,7 @@
 
 import dalvik.system.VMRuntime;
 import dalvik.system.VMStack;
+import java.io.BufferedInputStream;
 import java.io.Console;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -83,10 +84,9 @@
     private static Properties systemProperties;
 
     static {
-        // TODO: all three streams are buffered in Harmony.
         err = new PrintStream(new FileOutputStream(FileDescriptor.err));
         out = new PrintStream(new FileOutputStream(FileDescriptor.out));
-        in = new FileInputStream(FileDescriptor.in);
+        in = new BufferedInputStream(new FileInputStream(FileDescriptor.in));
         lineSeparator = System.getProperty("line.separator");
     }
 
@@ -455,7 +455,7 @@
      */
     public static String clearProperty(String key) {
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
         if (key.isEmpty()) {
             throw new IllegalArgumentException();
@@ -679,7 +679,7 @@
 
         private String toNonNullString(Object o) {
             if (o == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("o == null");
             }
             return (String) o;
         }
diff --git a/luni/src/main/java/java/lang/Thread.java b/luni/src/main/java/java/lang/Thread.java
index a61f669..210b90c 100644
--- a/luni/src/main/java/java/lang/Thread.java
+++ b/luni/src/main/java/java/lang/Thread.java
@@ -232,7 +232,7 @@
      */
     public Thread(Runnable runnable, String threadName) {
         if (threadName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("threadName == null");
         }
 
         create(null, runnable, threadName, 0);
@@ -252,7 +252,7 @@
      */
     public Thread(String threadName) {
         if (threadName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("threadName == null");
         }
 
         create(null, null, threadName, 0);
@@ -296,7 +296,7 @@
      */
     public Thread(ThreadGroup group, Runnable runnable, String threadName) {
         if (threadName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("threadName == null");
         }
 
         create(group, runnable, threadName, 0);
@@ -317,7 +317,7 @@
      */
     public Thread(ThreadGroup group, String threadName) {
         if (threadName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("threadName == null");
         }
 
         create(group, null, threadName, 0);
@@ -346,7 +346,7 @@
      */
     public Thread(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
         if (threadName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("threadName == null");
         }
         create(group, runnable, threadName, stackSize);
     }
@@ -943,7 +943,7 @@
      */
     public final void setName(String threadName) {
         if (threadName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("threadName == null");
         }
 
         name = threadName;
diff --git a/luni/src/main/java/java/lang/Throwable.java b/luni/src/main/java/java/lang/Throwable.java
index b561832..b20b882 100644
--- a/luni/src/main/java/java/lang/Throwable.java
+++ b/luni/src/main/java/java/lang/Throwable.java
@@ -23,6 +23,7 @@
 import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import libcore.util.EmptyArray;
 
@@ -63,13 +64,13 @@
      * Throwables suppressed by this throwable. Null when suppressed exceptions
      * are disabled.
      */
-    private List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
+    private List<Throwable> suppressedExceptions = Collections.emptyList();
 
     /**
      * An intermediate representation of the stack trace.  This field may
      * be accessed by the VM; do not rename.
      */
-    private volatile Object stackState;
+    private transient volatile Object stackState;
 
     /**
      * A fully-expanded representation of the stack trace.
@@ -218,9 +219,9 @@
      */
     public void setStackTrace(StackTraceElement[] trace) {
         StackTraceElement[] newTrace = trace.clone();
-        for (StackTraceElement element : newTrace) {
-            if (element == null) {
-                throw new NullPointerException();
+        for (int i = 0; i < newTrace.length; i++) {
+            if (newTrace[i] == null) {
+                throw new NullPointerException("trace[" + i + "] == null");
             }
         }
         stackTrace = newTrace;
@@ -412,12 +413,17 @@
      */
     public final void addSuppressed(Throwable throwable) {
         if (throwable == this) {
-            throw new IllegalArgumentException("suppressed == this");
+            throw new IllegalArgumentException("throwable == this");
         }
         if (throwable == null) {
-            throw new NullPointerException("suppressed == null");
+            throw new NullPointerException("throwable == null");
         }
         if (suppressedExceptions != null) {
+            // suppressed exceptions are enabled
+            if (suppressedExceptions.isEmpty()) {
+                // ensure we have somewhere to place suppressed exceptions
+                suppressedExceptions = new ArrayList<Throwable>(1);
+            }
             suppressedExceptions.add(throwable);
         }
     }
@@ -429,7 +435,7 @@
      * @hide 1.7
      */
     public final Throwable[] getSuppressed() {
-        return (suppressedExceptions != null)
+        return (suppressedExceptions != null && !suppressedExceptions.isEmpty())
                 ? suppressedExceptions.toArray(new Throwable[suppressedExceptions.size()])
                 : EmptyArray.THROWABLE;
     }
diff --git a/luni/src/main/java/java/lang/ref/FinalizerReference.java b/luni/src/main/java/java/lang/ref/FinalizerReference.java
index aadf1f6..14eaae4 100644
--- a/luni/src/main/java/java/lang/ref/FinalizerReference.java
+++ b/luni/src/main/java/java/lang/ref/FinalizerReference.java
@@ -20,33 +20,39 @@
  * @hide
  */
 public final class FinalizerReference<T> extends Reference<T> {
+    // This queue contains those objects eligible for finalization.
     public static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
 
-    private static FinalizerReference head = null;
+    // Guards the list (not the queue).
+    private static final Object LIST_LOCK = new Object();
 
+    // This list contains a FinalizerReference for every finalizable object in the heap.
+    // Objects in this list may or may not be eligible for finalization yet.
+    private static FinalizerReference<?> head = null;
+
+    // The links used to construct the list.
+    private FinalizerReference<?> prev;
+    private FinalizerReference<?> next;
+
+    // When the GC wants something finalized, it moves it from the 'referent' field to
+    // the 'zombie' field instead.
     private T zombie;
 
-    private FinalizerReference prev;
-
-    private FinalizerReference next;
-
     public FinalizerReference(T r, ReferenceQueue<? super T> q) {
         super(r, q);
     }
 
-    @Override
-    public T get() {
+    @Override public T get() {
         return zombie;
     }
 
-    @Override
-    public void clear() {
+    @Override public void clear() {
         zombie = null;
     }
 
-    static void add(Object referent) {
+    public static void add(Object referent) {
         FinalizerReference<?> reference = new FinalizerReference<Object>(referent, queue);
-        synchronized (FinalizerReference.class) {
+        synchronized (LIST_LOCK) {
             reference.prev = null;
             reference.next = head;
             if (head != null) {
@@ -56,10 +62,10 @@
         }
     }
 
-    public static void remove(FinalizerReference reference) {
-        synchronized (FinalizerReference.class) {
-            FinalizerReference next = reference.next;
-            FinalizerReference prev = reference.prev;
+    public static void remove(FinalizerReference<?> reference) {
+        synchronized (LIST_LOCK) {
+            FinalizerReference<?> next = reference.next;
+            FinalizerReference<?> prev = reference.prev;
             reference.next = null;
             reference.prev = null;
             if (prev != null) {
@@ -74,30 +80,50 @@
     }
 
     /**
-     * Returns once all currently-enqueued references have been finalized.
+     * Waits for all currently-enqueued references to be finalized.
      */
     public static void finalizeAllEnqueued() throws InterruptedException {
         Sentinel sentinel = new Sentinel();
-        FinalizerReference<Object> reference = new FinalizerReference<Object>(null, queue);
-        reference.zombie = sentinel;
-        reference.enqueueInternal();
+        enqueueSentinelReference(sentinel);
         sentinel.awaitFinalization();
     }
 
+    private static void enqueueSentinelReference(Sentinel sentinel) {
+        synchronized (LIST_LOCK) {
+            // When a finalizable object is allocated, a FinalizerReference is added to the list.
+            // We search the list for that FinalizerReference (it should be at or near the head),
+            // and then put it on the queue so that it can be finalized.
+            for (FinalizerReference<?> r = head; r != null; r = r.next) {
+                if (r.referent == sentinel) {
+                    FinalizerReference<Sentinel> sentinelReference = (FinalizerReference<Sentinel>) r;
+                    sentinelReference.referent = null;
+                    sentinelReference.zombie = sentinel;
+                    sentinelReference.enqueueInternal();
+                    return;
+                }
+            }
+        }
+        // We just created a finalizable object and still hold a reference to it.
+        // It must be on the list.
+        throw new AssertionError("newly-created live Sentinel not on list!");
+    }
+
     /**
      * A marker object that we can immediately enqueue. When this object's
      * finalize() method is called, we know all previously-enqueued finalizable
      * references have been finalized.
-     *
-     * <p>Each instance of this class will be finalized twice as it is enqueued
-     * directly and by the garbage collector.
      */
     private static class Sentinel {
         boolean finalized = false;
+
         @Override protected synchronized void finalize() throws Throwable {
+            if (finalized) {
+                throw new AssertionError();
+            }
             finalized = true;
             notifyAll();
         }
+
         synchronized void awaitFinalization() throws InterruptedException {
             while (!finalized) {
                 wait();
diff --git a/luni/src/main/java/java/lang/ref/Reference.java b/luni/src/main/java/java/lang/ref/Reference.java
index 85fbb04..9cf49a7 100644
--- a/luni/src/main/java/java/lang/ref/Reference.java
+++ b/luni/src/main/java/java/lang/ref/Reference.java
@@ -55,8 +55,7 @@
      * VM requirement: this field <em>must</em> be called "queue"
      * and be a java.lang.ref.ReferenceQueue.
      */
-    @SuppressWarnings("unchecked")
-    volatile ReferenceQueue queue;
+    volatile ReferenceQueue<? super T> queue;
 
     /**
      * Used internally by java.lang.ref.ReferenceQueue.
@@ -82,7 +81,7 @@
     Reference() {
     }
 
-    Reference(T r, ReferenceQueue q) {
+    Reference(T r, ReferenceQueue<? super T> q) {
         referent = r;
         queue = q;
     }
diff --git a/luni/src/main/java/java/lang/ref/ReferenceQueue.java b/luni/src/main/java/java/lang/ref/ReferenceQueue.java
index 6c9b4d5..2b8089c 100644
--- a/luni/src/main/java/java/lang/ref/ReferenceQueue.java
+++ b/luni/src/main/java/java/lang/ref/ReferenceQueue.java
@@ -131,8 +131,6 @@
      *
      * @param reference
      *            reference object to be enqueued.
-     * @return boolean true if reference is enqueued. false if reference failed
-     *         to enqueue.
      */
     synchronized void enqueue(Reference<? extends T> reference) {
         if (head == null) {
@@ -145,7 +143,7 @@
     }
 
     /** @hide */
-    public static Reference unenqueued = null;
+    public static Reference<?> unenqueued = null;
 
     static void add(Reference<?> list) {
         synchronized (ReferenceQueue.class) {
diff --git a/luni/src/main/java/java/lang/reflect/GenericArrayType.java b/luni/src/main/java/java/lang/reflect/GenericArrayType.java
index 6344019..fc03f78 100644
--- a/luni/src/main/java/java/lang/reflect/GenericArrayType.java
+++ b/luni/src/main/java/java/lang/reflect/GenericArrayType.java
@@ -36,4 +36,4 @@
      *             instantiated for some reason
      */
     Type getGenericComponentType();
-}
\ No newline at end of file
+}
diff --git a/luni/src/main/java/java/lang/reflect/Proxy.java b/luni/src/main/java/java/lang/reflect/Proxy.java
index a24514d..3b10887 100644
--- a/luni/src/main/java/java/lang/reflect/Proxy.java
+++ b/luni/src/main/java/java/lang/reflect/Proxy.java
@@ -89,13 +89,13 @@
             Class<?>... interfaces) throws IllegalArgumentException {
         // check that interfaces are a valid array of visible interfaces
         if (interfaces == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("interfaces == null");
         }
         String commonPackageName = null;
         for (int i = 0, length = interfaces.length; i < length; i++) {
             Class<?> next = interfaces[i];
             if (next == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("interfaces[" + i + "] == null");
             }
             String name = next.getName();
             if (!next.isInterface()) {
@@ -206,7 +206,7 @@
             Class<?>[] interfaces, InvocationHandler h)
             throws IllegalArgumentException {
         if (h == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("h == null");
         }
         try {
             return getProxyClass(loader, interfaces).getConstructor(
@@ -241,7 +241,7 @@
      */
     public static boolean isProxyClass(Class<?> cl) {
         if (cl == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("cl == null");
         }
         synchronized (proxyCache) {
             return proxyCache.containsKey(cl);
diff --git a/luni/src/main/java/java/math/BigDecimal.java b/luni/src/main/java/java/math/BigDecimal.java
index 3a5f3cd..335e3bc 100644
--- a/luni/src/main/java/java/math/BigDecimal.java
+++ b/luni/src/main/java/java/math/BigDecimal.java
@@ -276,7 +276,7 @@
         long newScale; // the new scale
 
         if (in == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("in == null");
         }
         if ((last >= in.length) || (offset < 0) || (len <= 0) || (last < 0)) {
             throw new NumberFormatException("Bad offset/length: offset=" + offset +
@@ -601,7 +601,7 @@
      */
     public BigDecimal(BigInteger unscaledVal, int scale) {
         if (unscaledVal == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("unscaledVal == null");
         }
         this.scale = scale;
         setUnscaledValue(unscaledVal);
@@ -1059,7 +1059,7 @@
     public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) {
         // Let be: this = [u1,s1]  and  divisor = [u2,s2]
         if (roundingMode == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("roundingMode == null");
         }
         if (divisor.isZero()) {
             throw new ArithmeticException("Division by zero");
@@ -1916,7 +1916,7 @@
      */
     public BigDecimal setScale(int newScale, RoundingMode roundingMode) {
         if (roundingMode == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("roundingMode == null");
         }
         long diffScale = newScale - (long)scale;
         // Let be:  'this' = [u,s]
diff --git a/luni/src/main/java/java/math/BigInt.java b/luni/src/main/java/java/math/BigInt.java
index 1768676..614dbb4 100644
--- a/luni/src/main/java/java/math/BigInt.java
+++ b/luni/src/main/java/java/math/BigInt.java
@@ -153,7 +153,7 @@
      */
     String checkString(String s, int base) {
         if (s == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("s == null");
         }
         // A valid big integer consists of an optional '-' or '+' followed by
         // one or more digit characters appropriate to the given base,
diff --git a/luni/src/main/java/java/net/CookieStore.java b/luni/src/main/java/java/net/CookieStore.java
index d09b7e8..619d65c 100644
--- a/luni/src/main/java/java/net/CookieStore.java
+++ b/luni/src/main/java/java/net/CookieStore.java
@@ -100,4 +100,4 @@
      * @return true if any cookies were removed as a result of this call.
      */
     boolean removeAll();
-}
\ No newline at end of file
+}
diff --git a/luni/src/main/java/java/net/DatagramSocket.java b/luni/src/main/java/java/net/DatagramSocket.java
index 2b468fa..c01f3af 100644
--- a/luni/src/main/java/java/net/DatagramSocket.java
+++ b/luni/src/main/java/java/net/DatagramSocket.java
@@ -244,7 +244,7 @@
         checkOpen();
         ensureBound();
         if (pack == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("pack == null");
         }
         if (pendingConnectException != null) {
             throw new SocketException("Pending connect failure", pendingConnectException);
@@ -295,7 +295,7 @@
      */
     public void setNetworkInterface(NetworkInterface netInterface) throws SocketException {
         if (netInterface == null) {
-            throw new NullPointerException("networkInterface == null");
+            throw new NullPointerException("netInterface == null");
         }
         try {
             Libcore.os.setsockoptIfreq(impl.fd, SOL_SOCKET, SO_BINDTODEVICE, netInterface.getName());
@@ -374,7 +374,7 @@
      */
     protected DatagramSocket(DatagramSocketImpl socketImpl) {
         if (socketImpl == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("socketImpl == null");
         }
         impl = socketImpl;
     }
diff --git a/luni/src/main/java/java/net/NetworkInterface.java b/luni/src/main/java/java/net/NetworkInterface.java
index e06b811..ad81f32 100644
--- a/luni/src/main/java/java/net/NetworkInterface.java
+++ b/luni/src/main/java/java/net/NetworkInterface.java
@@ -122,7 +122,9 @@
 
     private static void collectIpv6Addresses(String interfaceName, int interfaceIndex,
             List<InetAddress> addresses, List<InterfaceAddress> interfaceAddresses) throws SocketException {
-        // Format of /proc/net/if_inet6 (all numeric fields are implicit hex).
+        // Format of /proc/net/if_inet6.
+        // All numeric fields are implicit hex,
+        // but not necessarily two-digit (http://code.google.com/p/android/issues/detail?id=34022).
         // 1. IPv6 address
         // 2. interface index
         // 3. prefix length
@@ -130,6 +132,7 @@
         // 5. flags
         // 6. interface name
         // "00000000000000000000000000000001 01 80 10 80       lo"
+        // "fe800000000000000000000000000000 407 40 20 80    wlan0"
         BufferedReader in = null;
         try {
             in = new BufferedReader(new FileReader("/proc/net/if_inet6"));
@@ -139,13 +142,22 @@
                 if (!line.endsWith(suffix)) {
                     continue;
                 }
+
+                // Extract the IPv6 address.
                 byte[] addressBytes = new byte[16];
                 for (int i = 0; i < addressBytes.length; ++i) {
                     addressBytes[i] = (byte) Integer.parseInt(line.substring(2*i, 2*i + 2), 16);
                 }
-                short prefixLength = Short.parseShort(line.substring(36, 38), 16);
-                Inet6Address inet6Address = new Inet6Address(addressBytes, null, interfaceIndex);
 
+                // Extract the prefix length.
+                // Skip the IPv6 address and its trailing space.
+                int prefixLengthStart = 32 + 1;
+                // Skip the interface index and its trailing space.
+                prefixLengthStart = line.indexOf(' ', prefixLengthStart) + 1;
+                int prefixLengthEnd = line.indexOf(' ', prefixLengthStart);
+                short prefixLength = Short.parseShort(line.substring(prefixLengthStart, prefixLengthEnd), 16);
+
+                Inet6Address inet6Address = new Inet6Address(addressBytes, null, interfaceIndex);
                 addresses.add(inet6Address);
                 interfaceAddresses.add(new InterfaceAddress(inet6Address, prefixLength));
             }
diff --git a/luni/src/main/java/java/net/PlainDatagramSocketImpl.java b/luni/src/main/java/java/net/PlainDatagramSocketImpl.java
index 5d01469..3226527 100644
--- a/luni/src/main/java/java/net/PlainDatagramSocketImpl.java
+++ b/luni/src/main/java/java/net/PlainDatagramSocketImpl.java
@@ -216,6 +216,8 @@
             Libcore.os.connect(fd, InetAddress.UNSPECIFIED, 0);
         } catch (ErrnoException errnoException) {
             throw new AssertionError(errnoException);
+        } catch (SocketException ignored) {
+            // Thrown if the socket has already been closed, but this method can't throw anything.
         }
         connectedPort = -1;
         connectedAddress = null;
diff --git a/luni/src/main/java/java/net/URISyntaxException.java b/luni/src/main/java/java/net/URISyntaxException.java
index e08f444..957ea31 100644
--- a/luni/src/main/java/java/net/URISyntaxException.java
+++ b/luni/src/main/java/java/net/URISyntaxException.java
@@ -49,8 +49,10 @@
     public URISyntaxException(String input, String reason, int index) {
         super(reason);
 
-        if (input == null || reason == null) {
-            throw new NullPointerException();
+        if (input == null) {
+            throw new NullPointerException("input == null");
+        } else if (reason == null) {
+            throw new NullPointerException("reason == null");
         }
 
         if (index < -1) {
@@ -76,8 +78,10 @@
     public URISyntaxException(String input, String reason) {
         super(reason);
 
-        if (input == null || reason == null) {
-            throw new NullPointerException();
+        if (input == null) {
+            throw new NullPointerException("input == null");
+        } else if (reason == null) {
+            throw new NullPointerException("reason == null");
         }
 
         this.input = input;
diff --git a/luni/src/main/java/java/net/URLClassLoader.java b/luni/src/main/java/java/net/URLClassLoader.java
index 1c8bc43..efb7531 100644
--- a/luni/src/main/java/java/net/URLClassLoader.java
+++ b/luni/src/main/java/java/net/URLClassLoader.java
@@ -822,7 +822,7 @@
         while (!searchList.isEmpty()) {
             URL nextCandidate = searchList.remove(0);
             if (nextCandidate == null) {
-                throw new NullPointerException("A URL is null");
+                throw new NullPointerException("nextCandidate == null");
             }
             if (!handlerMap.containsKey(nextCandidate)) {
                 URLHandler result;
diff --git a/luni/src/main/java/java/net/URLConnection.java b/luni/src/main/java/java/net/URLConnection.java
index c832bfb..18a264e 100644
--- a/luni/src/main/java/java/net/URLConnection.java
+++ b/luni/src/main/java/java/net/URLConnection.java
@@ -948,11 +948,12 @@
     }
 
     /**
-     * Sets the maximum time to wait for a connect to complete before giving up.
+     * Sets the maximum time in milliseconds to wait while connecting.
      * Connecting to a server will fail with a {@link SocketTimeoutException} if
      * the timeout elapses before a connection is established. The default value
-     * of {@code 0} disables connect timeouts; connect attempts may wait
-     * indefinitely.
+     * of {@code 0} causes us to do a blocking connect. This does not mean we
+     * will never time out, but it probably means you'll get a TCP timeout
+     * after several minutes.
      *
      * <p><strong>Warning:</strong> if the hostname resolves to multiple IP
      * addresses, this client will try each in <a
@@ -961,7 +962,7 @@
      * elapse before the connect attempt throws an exception. Host names that
      * support both IPv6 and IPv4 always have at least 2 IP addresses.
      *
-     * @param timeoutMillis the connect timeout in milliseconds. Non-negative.
+     * @throws IllegalArgumentException if {@code timeoutMillis &lt; 0}.
      */
     public void setConnectTimeout(int timeoutMillis) {
         if (timeoutMillis < 0) {
@@ -971,8 +972,7 @@
     }
 
     /**
-     * Returns the connect timeout in milliseconds, or {@code 0} if connect
-     * attempts never timeout.
+     * Returns the connect timeout in milliseconds. (See {#setConnectTimeout}.)
      */
     public int getConnectTimeout() {
         return connectTimeout;
diff --git a/luni/src/main/java/java/nio/Buffer.java b/luni/src/main/java/java/nio/Buffer.java
index c3840a5..b90744b 100644
--- a/luni/src/main/java/java/nio/Buffer.java
+++ b/luni/src/main/java/java/nio/Buffer.java
@@ -271,7 +271,7 @@
 
     final void checkWritable() {
         if (isReadOnly()) {
-            throw new IllegalArgumentException("read-only buffer");
+            throw new IllegalArgumentException("Read-only buffer");
         }
     }
 
diff --git a/luni/src/main/java/java/nio/ByteBuffer.java b/luni/src/main/java/java/nio/ByteBuffer.java
index ef725c1..6a3624a 100644
--- a/luni/src/main/java/java/nio/ByteBuffer.java
+++ b/luni/src/main/java/java/nio/ByteBuffer.java
@@ -47,7 +47,7 @@
      */
     public static ByteBuffer allocate(int capacity) {
         if (capacity < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("capacity < 0: " + capacity);
         }
         return new ReadWriteHeapByteBuffer(capacity);
     }
@@ -63,7 +63,7 @@
      */
     public static ByteBuffer allocateDirect(int capacity) {
         if (capacity < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("capacity < 0: " + capacity);
         }
         return new ReadWriteDirectByteBuffer(capacity);
     }
diff --git a/luni/src/main/java/java/nio/CharBuffer.java b/luni/src/main/java/java/nio/CharBuffer.java
index 03bac04..6429ae2 100644
--- a/luni/src/main/java/java/nio/CharBuffer.java
+++ b/luni/src/main/java/java/nio/CharBuffer.java
@@ -49,7 +49,7 @@
      */
     public static CharBuffer allocate(int capacity) {
         if (capacity < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("capacity < 0: " + capacity);
         }
         return new ReadWriteCharArrayBuffer(capacity);
     }
@@ -500,7 +500,7 @@
      */
     public CharBuffer put(CharBuffer src) {
         if (src == this) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("src == this");
         }
         if (src.remaining() > remaining()) {
             throw new BufferOverflowException();
@@ -734,7 +734,7 @@
             if (remaining == 0) {
                 return -1;
             }
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("target == this");
         }
         if (remaining == 0) {
             return limit > 0 && target.remaining() == 0 ? 0 : -1;
diff --git a/luni/src/main/java/java/nio/DatagramChannelImpl.java b/luni/src/main/java/java/nio/DatagramChannelImpl.java
index a0e064d..4d2fc5a 100644
--- a/luni/src/main/java/java/nio/DatagramChannelImpl.java
+++ b/luni/src/main/java/java/nio/DatagramChannelImpl.java
@@ -448,7 +448,7 @@
      */
     private void checkNotNull(ByteBuffer source) {
         if (source == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("source == null");
         }
     }
 
diff --git a/luni/src/main/java/java/nio/DoubleBuffer.java b/luni/src/main/java/java/nio/DoubleBuffer.java
index c495592..8d90f89 100644
--- a/luni/src/main/java/java/nio/DoubleBuffer.java
+++ b/luni/src/main/java/java/nio/DoubleBuffer.java
@@ -47,7 +47,7 @@
      */
     public static DoubleBuffer allocate(int capacity) {
         if (capacity < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("capacity < 0: " + capacity);
         }
         return new ReadWriteDoubleArrayBuffer(capacity);
     }
@@ -438,7 +438,7 @@
      */
     public DoubleBuffer put(DoubleBuffer src) {
         if (src == this) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("src == this");
         }
         if (src.remaining() > remaining()) {
             throw new BufferOverflowException();
diff --git a/luni/src/main/java/java/nio/FileChannelImpl.java b/luni/src/main/java/java/nio/FileChannelImpl.java
index 76bad51..075243a 100644
--- a/luni/src/main/java/java/nio/FileChannelImpl.java
+++ b/luni/src/main/java/java/nio/FileChannelImpl.java
@@ -442,7 +442,7 @@
     public FileChannel truncate(long size) throws IOException {
         checkOpen();
         if (size < 0) {
-            throw new IllegalArgumentException("size: " + size);
+            throw new IllegalArgumentException("size < 0: " + size);
         }
         checkWritable();
         if (size < size()) {
@@ -457,7 +457,7 @@
 
     public int write(ByteBuffer buffer, long position) throws IOException {
         if (position < 0) {
-            throw new IllegalArgumentException("position: " + position);
+            throw new IllegalArgumentException("position < 0: " + position);
         }
         return writeImpl(buffer, position);
     }
diff --git a/luni/src/main/java/java/nio/FloatBuffer.java b/luni/src/main/java/java/nio/FloatBuffer.java
index ec361d6..814eb53 100644
--- a/luni/src/main/java/java/nio/FloatBuffer.java
+++ b/luni/src/main/java/java/nio/FloatBuffer.java
@@ -46,7 +46,7 @@
      */
     public static FloatBuffer allocate(int capacity) {
         if (capacity < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("capacity < 0: " + capacity);
         }
         return new ReadWriteFloatArrayBuffer(capacity);
     }
@@ -437,7 +437,7 @@
      */
     public FloatBuffer put(FloatBuffer src) {
         if (src == this) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("src == this");
         }
         if (src.remaining() > remaining()) {
             throw new BufferOverflowException();
diff --git a/luni/src/main/java/java/nio/IntBuffer.java b/luni/src/main/java/java/nio/IntBuffer.java
index 9cc05ff..0ff758a 100644
--- a/luni/src/main/java/java/nio/IntBuffer.java
+++ b/luni/src/main/java/java/nio/IntBuffer.java
@@ -44,7 +44,7 @@
      */
     public static IntBuffer allocate(int capacity) {
         if (capacity < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("capacity < 0: " + capacity);
         }
         return new ReadWriteIntArrayBuffer(capacity);
     }
@@ -423,7 +423,7 @@
      */
     public IntBuffer put(IntBuffer src) {
         if (src == this) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("src == this");
         }
         if (src.remaining() > remaining()) {
             throw new BufferOverflowException();
diff --git a/luni/src/main/java/java/nio/LongBuffer.java b/luni/src/main/java/java/nio/LongBuffer.java
index 27edd2e..1254ddb 100644
--- a/luni/src/main/java/java/nio/LongBuffer.java
+++ b/luni/src/main/java/java/nio/LongBuffer.java
@@ -46,7 +46,7 @@
      */
     public static LongBuffer allocate(int capacity) {
         if (capacity < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("capacity < 0: " + capacity);
         }
         return new ReadWriteLongArrayBuffer(capacity);
     }
@@ -427,7 +427,7 @@
      */
     public LongBuffer put(LongBuffer src) {
         if (src == this) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("src == this");
         }
         if (src.remaining() > remaining()) {
             throw new BufferOverflowException();
diff --git a/luni/src/main/java/java/nio/MappedByteBuffer.java b/luni/src/main/java/java/nio/MappedByteBuffer.java
index 39c4986..0e8bf09 100644
--- a/luni/src/main/java/java/nio/MappedByteBuffer.java
+++ b/luni/src/main/java/java/nio/MappedByteBuffer.java
@@ -45,7 +45,7 @@
     MappedByteBuffer(ByteBuffer directBuffer) {
         super(directBuffer.capacity, directBuffer.block);
         if (!directBuffer.isDirect()) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("directBuffer is not a direct buffer: " + directBuffer);
         }
         this.wrapped = (DirectByteBuffer) directBuffer;
         this.mapMode = null;
diff --git a/luni/src/main/java/java/nio/NIOAccess.java b/luni/src/main/java/java/nio/NIOAccess.java
index 361a37f..36c41cf 100644
--- a/luni/src/main/java/java/nio/NIOAccess.java
+++ b/luni/src/main/java/java/nio/NIOAccess.java
@@ -28,7 +28,7 @@
      * different than what the Harmony implementation calls a "base
      * address."
      *
-     * @param Buffer b the Buffer to be queried
+     * @param b the Buffer to be queried
      * @return the native pointer to the Buffer's data at its current
      * position, or 0 if there is none
      */
@@ -44,7 +44,7 @@
      * Returns the underlying Java array containing the data of the
      * given Buffer, or null if the Buffer is not backed by a Java array.
      *
-     * @param Buffer b the Buffer to be queried
+     * @param b the Buffer to be queried
      * @return the Java array containing the Buffer's data, or null if
      * there is none
      */
@@ -55,13 +55,14 @@
     /**
      * Returns the offset in bytes from the start of the underlying
      * Java array object containing the data of the given Buffer to
-     * the actual start of the data. This method is only meaningful if
-     * getBaseArray() returns non-null.
+     * the actual start of the data. The start of the data takes into
+     * account the Buffer's current position. This method is only
+     * meaningful if getBaseArray() returns non-null.
      *
-     * @param Buffer b the Buffer to be queried
+     * @param b the Buffer to be queried
      * @return the data offset in bytes to the start of this Buffer's data
      */
     static int getBaseArrayOffset(Buffer b) {
-        return b.hasArray() ? (b.arrayOffset() << b._elementSizeShift) : 0;
+        return b.hasArray() ? ((b.arrayOffset() + b.position) << b._elementSizeShift) : 0;
     }
 }
diff --git a/luni/src/main/java/java/nio/SelectorImpl.java b/luni/src/main/java/java/nio/SelectorImpl.java
index 05a6497..02fdf54 100644
--- a/luni/src/main/java/java/nio/SelectorImpl.java
+++ b/luni/src/main/java/java/nio/SelectorImpl.java
@@ -150,7 +150,7 @@
 
     @Override public int select(long timeout) throws IOException {
         if (timeout < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("timeout < 0: " + timeout);
         }
         // Our timeout is interpreted differently to Unix's --- 0 means block. See selectNow.
         return selectInternal((timeout == 0) ? -1 : timeout);
diff --git a/luni/src/main/java/java/nio/ShortBuffer.java b/luni/src/main/java/java/nio/ShortBuffer.java
index 052cf6b..d12a49e 100644
--- a/luni/src/main/java/java/nio/ShortBuffer.java
+++ b/luni/src/main/java/java/nio/ShortBuffer.java
@@ -46,7 +46,7 @@
      */
     public static ShortBuffer allocate(int capacity) {
         if (capacity < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("capacity < 0: " + capacity);
         }
         return new ReadWriteShortArrayBuffer(capacity);
     }
@@ -426,7 +426,7 @@
      */
     public ShortBuffer put(ShortBuffer src) {
         if (src == this) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("src == this");
         }
         if (src.remaining() > remaining()) {
             throw new BufferOverflowException();
diff --git a/luni/src/main/java/java/nio/SocketChannelImpl.java b/luni/src/main/java/java/nio/SocketChannelImpl.java
index 9b26812..ff2c157 100644
--- a/luni/src/main/java/java/nio/SocketChannelImpl.java
+++ b/luni/src/main/java/java/nio/SocketChannelImpl.java
@@ -318,7 +318,7 @@
     @Override
     public int write(ByteBuffer src) throws IOException {
         if (src == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("src == null");
         }
         checkOpenConnected();
         if (!src.hasRemaining()) {
@@ -412,7 +412,7 @@
      */
     static InetSocketAddress validateAddress(SocketAddress socketAddress) {
         if (socketAddress == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("socketAddress == null");
         }
         if (!(socketAddress instanceof InetSocketAddress)) {
             throw new UnsupportedAddressTypeException();
diff --git a/luni/src/main/java/java/nio/channels/Channels.java b/luni/src/main/java/java/nio/channels/Channels.java
index 3af1465..b59eeac 100644
--- a/luni/src/main/java/java/nio/channels/Channels.java
+++ b/luni/src/main/java/java/nio/channels/Channels.java
@@ -150,7 +150,7 @@
     public static Reader newReader(ReadableByteChannel channel,
             String charsetName) {
         if (charsetName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("charsetName == null");
         }
         return newReader(channel, Charset.forName(charsetName).newDecoder(), -1);
     }
@@ -193,7 +193,7 @@
     public static Writer newWriter(WritableByteChannel channel,
             String charsetName) {
         if (charsetName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("charsetName == null");
         }
         return newWriter(channel, Charset.forName(charsetName).newEncoder(), -1);
     }
@@ -207,7 +207,7 @@
 
         ChannelInputStream(ReadableByteChannel channel) {
             if (channel == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("channel == null");
             }
             this.channel = channel;
         }
@@ -247,7 +247,7 @@
 
         ChannelOutputStream(WritableByteChannel channel) {
             if (channel == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("channel == null");
             }
             this.channel = channel;
         }
@@ -289,7 +289,7 @@
 
         InputStreamChannel(InputStream inputStream) {
             if (inputStream == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("inputStream == null");
             }
             this.inputStream = inputStream;
         }
@@ -328,7 +328,7 @@
 
         OutputStreamChannel(OutputStream outputStream) {
             if (outputStream == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("outputStream == null");
             }
             this.outputStream = outputStream;
         }
diff --git a/luni/src/main/java/java/nio/channels/FileLock.java b/luni/src/main/java/java/nio/channels/FileLock.java
index 0916be0..4cdcc27 100644
--- a/luni/src/main/java/java/nio/channels/FileLock.java
+++ b/luni/src/main/java/java/nio/channels/FileLock.java
@@ -98,7 +98,7 @@
      */
     protected FileLock(FileChannel channel, long position, long size, boolean shared) {
         if (position < 0 || size < 0 || position + size < 0) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("position=" + position + " size=" + size);
         }
         this.channel = channel;
         this.position = position;
diff --git a/luni/src/main/java/java/nio/charset/CharsetDecoder.java b/luni/src/main/java/java/nio/charset/CharsetDecoder.java
index f67dbbc..1559db4 100644
--- a/luni/src/main/java/java/nio/charset/CharsetDecoder.java
+++ b/luni/src/main/java/java/nio/charset/CharsetDecoder.java
@@ -590,7 +590,7 @@
      */
     public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) {
         if (newAction == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("newAction == null");
         }
         malformedInputAction = newAction;
         implOnMalformedInput(newAction);
@@ -612,7 +612,7 @@
      */
     public final CharsetDecoder onUnmappableCharacter(CodingErrorAction newAction) {
         if (newAction == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("newAction == null");
         }
         unmappableCharacterAction = newAction;
         implOnUnmappableCharacter(newAction);
diff --git a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
index 3ad46d7..8b32efa 100644
--- a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
+++ b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
@@ -16,7 +16,7 @@
 
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
-import libcore.icu.ErrorCode;
+import libcore.icu.ICU;
 import libcore.icu.NativeConverter;
 import libcore.util.EmptyArray;
 
@@ -46,7 +46,6 @@
     // is inherently thread-unsafe so we don't have to worry about synchronization.
     private int inEnd;
     private int outEnd;
-    private int ec;
 
     public static CharsetDecoderICU newInstance(Charset cs, String icuCanonicalName) {
         // This complexity is necessary to ensure that even if the constructor, superclass
@@ -84,10 +83,7 @@
     }
 
     private void updateCallback() {
-        ec = NativeConverter.setCallbackDecode(converterHandle, this);
-        if (ErrorCode.isFailure(ec)) {
-            throw ErrorCode.throwException(ec);
-        }
+        NativeConverter.setCallbackDecode(converterHandle, this);
     }
 
     @Override protected void implReset() {
@@ -99,7 +95,6 @@
         input = null;
         allocatedInput = null;
         allocatedOutput = null;
-        ec = 0;
         inEnd = 0;
         outEnd = 0;
     }
@@ -114,16 +109,14 @@
             data[OUTPUT_OFFSET] = getArray(out);
             data[INVALID_BYTES] = 0; // Make sure we don't see earlier errors.
 
-            ec = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, true);
-            if (ErrorCode.isFailure(ec)) {
-                if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
+            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, true);
+            if (ICU.U_FAILURE(error)) {
+                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
                     return CoderResult.OVERFLOW;
-                } else if (ec == ErrorCode.U_TRUNCATED_CHAR_FOUND) {
+                } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) {
                     if (data[INPUT_OFFSET] > 0) {
                         return CoderResult.malformedForLength(data[INPUT_OFFSET]);
                     }
-                } else {
-                    throw ErrorCode.throwException(ec);
                 }
             }
             return CoderResult.UNDERFLOW;
@@ -142,13 +135,17 @@
         data[OUTPUT_OFFSET]= getArray(out);
 
         try {
-            ec = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, false);
-            if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
-                return CoderResult.OVERFLOW;
-            } else if (ec == ErrorCode.U_INVALID_CHAR_FOUND) {
-                return CoderResult.unmappableForLength(data[INVALID_BYTES]);
-            } else if (ec == ErrorCode.U_ILLEGAL_CHAR_FOUND) {
-                return CoderResult.malformedForLength(data[INVALID_BYTES]);
+            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, false);
+            if (ICU.U_FAILURE(error)) {
+                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
+                    return CoderResult.OVERFLOW;
+                } else if (error == ICU.U_INVALID_CHAR_FOUND) {
+                    return CoderResult.unmappableForLength(data[INVALID_BYTES]);
+                } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) {
+                    return CoderResult.malformedForLength(data[INVALID_BYTES]);
+                } else {
+                    throw new AssertionError(error);
+                }
             }
             // Decoding succeeded: give us more data.
             return CoderResult.UNDERFLOW;
diff --git a/luni/src/main/java/java/nio/charset/CharsetEncoder.java b/luni/src/main/java/java/nio/charset/CharsetEncoder.java
index 28b2cb8..8f02f96 100644
--- a/luni/src/main/java/java/nio/charset/CharsetEncoder.java
+++ b/luni/src/main/java/java/nio/charset/CharsetEncoder.java
@@ -706,11 +706,11 @@
             throw new IllegalArgumentException("replacement.length == 0");
         }
         if (replacement.length > maxBytesPerChar()) {
-            throw new IllegalArgumentException("replacement length > maxBytesPerChar: " +
+            throw new IllegalArgumentException("replacement.length > maxBytesPerChar: " +
                     replacement.length + " > " + maxBytesPerChar());
         }
         if (!isLegalReplacement(replacement)) {
-            throw new IllegalArgumentException("bad replacement: " + Arrays.toString(replacement));
+            throw new IllegalArgumentException("Bad replacement: " + Arrays.toString(replacement));
         }
         // It seems like a bug, but the RI doesn't clone, and we have tests that check we don't.
         this.replacementBytes = replacement;
diff --git a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
index cf071ca..76807b0 100644
--- a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
+++ b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
@@ -18,7 +18,7 @@
 import java.nio.CharBuffer;
 import java.util.HashMap;
 import java.util.Map;
-import libcore.icu.ErrorCode;
+import libcore.icu.ICU;
 import libcore.icu.NativeConverter;
 import libcore.util.EmptyArray;
 
@@ -61,7 +61,6 @@
     // is inherently thread-unsafe so we don't have to worry about synchronization.
     private int inEnd;
     private int outEnd;
-    private int ec;
 
     public static CharsetEncoderICU newInstance(Charset cs, String icuCanonicalName) {
         // This complexity is necessary to ensure that even if the constructor, superclass
@@ -112,10 +111,7 @@
     }
 
     private void updateCallback() {
-        ec = NativeConverter.setCallbackEncode(converterHandle, this);
-        if (ErrorCode.isFailure(ec)) {
-            throw ErrorCode.throwException(ec);
-        }
+        NativeConverter.setCallbackEncode(converterHandle, this);
     }
 
     @Override protected void implReset() {
@@ -127,7 +123,6 @@
         input = null;
         allocatedInput = null;
         allocatedOutput = null;
-        ec = 0;
         inEnd = 0;
         outEnd = 0;
     }
@@ -142,16 +137,14 @@
             data[OUTPUT_OFFSET] = getArray(out);
             data[INVALID_CHARS] = 0; // Make sure we don't see earlier errors.
 
-            ec = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, true);
-            if (ErrorCode.isFailure(ec)) {
-                if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
+            int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, true);
+            if (ICU.U_FAILURE(error)) {
+                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
                     return CoderResult.OVERFLOW;
-                } else if (ec == ErrorCode.U_TRUNCATED_CHAR_FOUND) {
+                } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) {
                     if (data[INPUT_OFFSET] > 0) {
                         return CoderResult.malformedForLength(data[INPUT_OFFSET]);
                     }
-                } else {
-                    throw ErrorCode.throwException(ec);
                 }
             }
             return CoderResult.UNDERFLOW;
@@ -171,16 +164,16 @@
         data[INVALID_CHARS] = 0; // Make sure we don't see earlier errors.
 
         try {
-            ec = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, false);
-            if (ErrorCode.isFailure(ec)) {
-                if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
+            int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, false);
+            if (ICU.U_FAILURE(error)) {
+                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
                     return CoderResult.OVERFLOW;
-                } else if (ec == ErrorCode.U_INVALID_CHAR_FOUND) {
+                } else if (error == ICU.U_INVALID_CHAR_FOUND) {
                     return CoderResult.unmappableForLength(data[INVALID_CHARS]);
-                } else if (ec == ErrorCode.U_ILLEGAL_CHAR_FOUND) {
+                } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) {
                     return CoderResult.malformedForLength(data[INVALID_CHARS]);
                 } else {
-                    throw new AssertionError("unexpected failure: " + ec);
+                    throw new AssertionError(error);
                 }
             }
             // Decoding succeeded: give us more data.
diff --git a/luni/src/main/java/java/nio/charset/Charsets.java b/luni/src/main/java/java/nio/charset/Charsets.java
index 1c2425a..826b12a 100644
--- a/luni/src/main/java/java/nio/charset/Charsets.java
+++ b/luni/src/main/java/java/nio/charset/Charsets.java
@@ -25,7 +25,7 @@
  *
  * @hide internal use only
  */
-public class Charsets {
+public final class Charsets {
     /**
      * A cheap and type-safe constant for the ISO-8859-1 Charset.
      */
diff --git a/luni/src/main/java/java/nio/charset/CoderResult.java b/luni/src/main/java/java/nio/charset/CoderResult.java
index 221cb32..3cc2673 100644
--- a/luni/src/main/java/java/nio/charset/CoderResult.java
+++ b/luni/src/main/java/java/nio/charset/CoderResult.java
@@ -121,7 +121,7 @@
                 return r;
             }
         }
-        throw new IllegalArgumentException("Length must be greater than 0; was " + length);
+        throw new IllegalArgumentException("length <= 0: " + length);
     }
 
     /**
@@ -149,7 +149,7 @@
                 return r;
             }
         }
-        throw new IllegalArgumentException("Length must be greater than 0; was " + length);
+        throw new IllegalArgumentException("length <= 0: " + length);
     }
 
     /**
diff --git a/luni/src/main/java/java/security/AlgorithmParameterGenerator.java b/luni/src/main/java/java/security/AlgorithmParameterGenerator.java
index daefa3c..3edc167 100644
--- a/luni/src/main/java/java/security/AlgorithmParameterGenerator.java
+++ b/luni/src/main/java/java/security/AlgorithmParameterGenerator.java
@@ -88,7 +88,7 @@
     public static AlgorithmParameterGenerator getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new AlgorithmParameterGenerator((AlgorithmParameterGeneratorSpi) sap.spi,
@@ -149,7 +149,7 @@
             throw new IllegalArgumentException();
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new AlgorithmParameterGenerator((AlgorithmParameterGeneratorSpi) spi, provider,
diff --git a/luni/src/main/java/java/security/AlgorithmParameters.java b/luni/src/main/java/java/security/AlgorithmParameters.java
index 8bbbe1b..073460e 100644
--- a/luni/src/main/java/java/security/AlgorithmParameters.java
+++ b/luni/src/main/java/java/security/AlgorithmParameters.java
@@ -92,7 +92,7 @@
     public static AlgorithmParameters getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new AlgorithmParameters((AlgorithmParametersSpi) sap.spi, sap.provider, algorithm);
@@ -120,7 +120,7 @@
             String provider) throws NoSuchAlgorithmException,
             NoSuchProviderException {
         if (provider == null || provider.isEmpty()) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("provider == null || provider.isEmpty()");
         }
         Provider p = Security.getProvider(provider);
         if (p == null) {
@@ -148,10 +148,10 @@
     public static AlgorithmParameters getInstance(String algorithm,
             Provider provider) throws NoSuchAlgorithmException {
         if (provider == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("provider == null");
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new AlgorithmParameters((AlgorithmParametersSpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/java/security/KeyFactory.java b/luni/src/main/java/java/security/KeyFactory.java
index 554885a..8d39003 100644
--- a/luni/src/main/java/java/security/KeyFactory.java
+++ b/luni/src/main/java/java/security/KeyFactory.java
@@ -76,7 +76,7 @@
     public static KeyFactory getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new KeyFactory((KeyFactorySpi) sap.spi, sap.provider, algorithm);
@@ -130,7 +130,7 @@
             throw new IllegalArgumentException();
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new KeyFactory((KeyFactorySpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/java/security/KeyPairGenerator.java b/luni/src/main/java/java/security/KeyPairGenerator.java
index d5851fa..5c17d79 100644
--- a/luni/src/main/java/java/security/KeyPairGenerator.java
+++ b/luni/src/main/java/java/security/KeyPairGenerator.java
@@ -80,7 +80,7 @@
     public static KeyPairGenerator getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         Object spi = sap.spi;
@@ -143,7 +143,7 @@
             throw new IllegalArgumentException();
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         if (spi instanceof KeyPairGenerator) {
diff --git a/luni/src/main/java/java/security/KeyStore.java b/luni/src/main/java/java/security/KeyStore.java
index c233a5b..3d856f7 100644
--- a/luni/src/main/java/java/security/KeyStore.java
+++ b/luni/src/main/java/java/security/KeyStore.java
@@ -110,7 +110,7 @@
      */
     public static KeyStore getInstance(String type) throws KeyStoreException {
         if (type == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("type == null");
         }
         try {
             Engine.SpiAndProvider sap = ENGINE.getInstance(type, null);
@@ -182,7 +182,7 @@
             throw new IllegalArgumentException();
         }
         if (type == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("type == null");
         }
         // return KeyStore instance
         try {
diff --git a/luni/src/main/java/java/security/KeyStoreSpi.java b/luni/src/main/java/java/security/KeyStoreSpi.java
index 01565f5..5ae9a72 100644
--- a/luni/src/main/java/java/security/KeyStoreSpi.java
+++ b/luni/src/main/java/java/security/KeyStoreSpi.java
@@ -414,14 +414,14 @@
         }
 
         char[] passW = null;
-        if (protParam instanceof KeyStore.PasswordProtection) {
-            try {
-                passW = ((KeyStore.PasswordProtection) protParam).getPassword();
-            } catch (IllegalStateException ee) {
-                throw new KeyStoreException("Password was destroyed", ee);
-            }
-        } else {
-            if (protParam instanceof KeyStore.CallbackHandlerProtection) {
+        if (protParam != null) {
+            if (protParam instanceof KeyStore.PasswordProtection) {
+                try {
+                    passW = ((KeyStore.PasswordProtection) protParam).getPassword();
+                } catch (IllegalStateException ee) {
+                    throw new KeyStoreException("Password was destroyed", ee);
+                }
+            } else if (protParam instanceof KeyStore.CallbackHandlerProtection) {
                 try {
                     passW = getPasswordFromCallBack(protParam);
                 } catch (Exception e) {
diff --git a/luni/src/main/java/java/security/MessageDigest.java b/luni/src/main/java/java/security/MessageDigest.java
index 3154028..6f1bf21 100644
--- a/luni/src/main/java/java/security/MessageDigest.java
+++ b/luni/src/main/java/java/security/MessageDigest.java
@@ -86,7 +86,7 @@
     public static MessageDigest getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         Object spi = sap.spi;
@@ -152,7 +152,7 @@
             throw new IllegalArgumentException();
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         if (spi instanceof MessageDigest) {
@@ -217,7 +217,7 @@
      */
     public void update(byte[] input) {
         if (input == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("input == null");
         }
         engineUpdate(input, 0, input.length);
     }
diff --git a/luni/src/main/java/java/security/Provider.java b/luni/src/main/java/java/security/Provider.java
index 2de3751..899625a 100644
--- a/luni/src/main/java/java/security/Provider.java
+++ b/luni/src/main/java/java/security/Provider.java
@@ -27,12 +27,13 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import org.apache.harmony.luni.util.TwoKeyHashMap;
 import org.apache.harmony.security.fortress.Services;
 
 /**
@@ -57,18 +58,18 @@
 
     // Contains "Service.Algorithm" and Provider.Service classes added using
     // putService()
-    private transient TwoKeyHashMap<String, String, Service> serviceTable;
+    private transient LinkedHashMap<String, Service> serviceTable;
 
     // Contains "Service.Alias" and Provider.Service classes added using
     // putService()
-    private transient TwoKeyHashMap<String, String, Service> aliasTable;
+    private transient LinkedHashMap<String, Service> aliasTable;
 
     // Contains "Service.Algorithm" and Provider.Service classes added using
     // put()
-    private transient TwoKeyHashMap<String, String, Service> propertyServiceTable;
+    private transient LinkedHashMap<String, Service> propertyServiceTable;
 
     // Contains "Service.Alias" and Provider.Service classes added using put()
-    private transient TwoKeyHashMap<String, String, Service> propertyAliasTable;
+    private transient LinkedHashMap<String, Service> propertyAliasTable;
 
     // The properties changed via put()
     private transient Properties changedProperties;
@@ -406,30 +407,32 @@
      */
     public synchronized Provider.Service getService(String type,
             String algorithm) {
-        if (type == null || algorithm == null) {
-            throw new NullPointerException();
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        } else if (algorithm == null) {
+            throw new NullPointerException("algorithm == null");
         }
 
         if (type.equals(lastServiceName) && algorithm.equalsIgnoreCase(lastAlgorithm)) {
             return returnedService;
         }
 
-        String alg = algorithm.toUpperCase(Locale.US);
+        String key = key(type, algorithm);
         Object o = null;
         if (serviceTable != null) {
-            o = serviceTable.get(type, alg);
+            o = serviceTable.get(key);
         }
         if (o == null && aliasTable != null) {
-            o = aliasTable.get(type, alg);
+            o = aliasTable.get(key);
         }
         if (o == null) {
             updatePropertyServiceTable();
         }
         if (o == null && propertyServiceTable != null) {
-            o = propertyServiceTable.get(type, alg);
+            o = propertyServiceTable.get(key);
         }
         if (o == null && propertyAliasTable != null) {
-            o = propertyAliasTable.get(type, alg);
+            o = propertyAliasTable.get(key);
         }
 
         if (o != null) {
@@ -454,9 +457,9 @@
             return lastServicesSet;
         }
         if (serviceTable != null) {
-            lastServicesSet = new HashSet<Service>(serviceTable.values());
+            lastServicesSet = new LinkedHashSet<Service>(serviceTable.values());
         } else {
-            lastServicesSet = new HashSet<Service>();
+            lastServicesSet = new LinkedHashSet<Service>();
         }
         if (propertyServiceTable != null) {
             lastServicesSet.addAll(propertyServiceTable.values());
@@ -474,22 +477,22 @@
      */
     protected synchronized void putService(Provider.Service s) {
         if (s == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("s == null");
         }
         if ("Provider".equals(s.getType())) { // Provider service type cannot be added
             return;
         }
         servicesChanged();
         if (serviceTable == null) {
-            serviceTable = new TwoKeyHashMap<String, String, Service>(128);
+            serviceTable = new LinkedHashMap<String, Service>(128);
         }
-        serviceTable.put(s.type, s.algorithm.toUpperCase(Locale.US), s);
+        serviceTable.put(key(s.type, s.algorithm), s);
         if (s.aliases != null) {
             if (aliasTable == null) {
-                aliasTable = new TwoKeyHashMap<String, String, Service>(256);
+                aliasTable = new LinkedHashMap<String, Service>(256);
             }
             for (String alias : s.getAliases()) {
-                aliasTable.put(s.type, alias.toUpperCase(Locale.US), s);
+                aliasTable.put(key(s.type, alias), s);
             }
         }
         serviceInfoToProperties(s);
@@ -506,15 +509,15 @@
      */
     protected synchronized void removeService(Provider.Service s) {
         if (s == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("s == null");
         }
         servicesChanged();
         if (serviceTable != null) {
-            serviceTable.remove(s.type, s.algorithm.toUpperCase(Locale.US));
+            serviceTable.remove(key(s.type, s.algorithm));
         }
         if (aliasTable != null && s.aliases != null) {
             for (String alias: s.getAliases()) {
-                aliasTable.remove(s.type, alias.toUpperCase(Locale.US));
+                aliasTable.remove(key(s.type, alias));
             }
         }
         serviceInfoFromProperties(s);
@@ -584,7 +587,7 @@
             serviceName = service_alias.substring(0, i);
             aliasName = service_alias.substring(i + 1);
             if (propertyAliasTable != null) {
-                propertyAliasTable.remove(serviceName, aliasName.toUpperCase(Locale.US));
+                propertyAliasTable.remove(key(serviceName, aliasName));
             }
             if (propertyServiceTable != null) {
                 for (Iterator<Service> it = propertyServiceTable.values().iterator(); it
@@ -608,12 +611,11 @@
             serviceName = k.substring(0, j);
             algorithm = k.substring(j + 1);
             if (propertyServiceTable != null) {
-                Provider.Service ser = propertyServiceTable.remove(serviceName,
-                        algorithm.toUpperCase(Locale.US));
+                Provider.Service ser = propertyServiceTable.remove(key(serviceName, algorithm));
                 if (ser != null && propertyAliasTable != null
                         && ser.aliases != null) {
                     for (String alias : ser.aliases) {
-                        propertyAliasTable.remove(serviceName, alias.toUpperCase(Locale.US));
+                        propertyAliasTable.remove(key(serviceName, alias));
                     }
                 }
             }
@@ -624,7 +626,7 @@
             serviceName = k.substring(0, j);
             algorithm = k.substring(j + 1, i);
             if (propertyServiceTable != null) {
-                Object o = propertyServiceTable.get(serviceName, algorithm.toUpperCase(Locale.US));
+                Object o = propertyServiceTable.get(key(serviceName, algorithm));
                 if (o != null) {
                     s = (Provider.Service) o;
                     s.attributes.remove(attribute);
@@ -667,20 +669,20 @@
                 serviceName = service_alias.substring(0, i);
                 aliasName = service_alias.substring(i + 1);
                 algorithm = value;
-                String algUp = algorithm.toUpperCase(Locale.US);
+                String propertyServiceTableKey = key(serviceName, algorithm);
                 Object o = null;
                 if (propertyServiceTable == null) {
-                    propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+                    propertyServiceTable = new LinkedHashMap<String, Service>(128);
                 } else {
-                    o = propertyServiceTable.get(serviceName, algUp);
+                    o = propertyServiceTable.get(propertyServiceTableKey);
                 }
                 if (o != null) {
                     s = (Provider.Service) o;
                     s.addAlias(aliasName);
                     if (propertyAliasTable == null) {
-                        propertyAliasTable = new TwoKeyHashMap<String, String, Service>(256);
+                        propertyAliasTable = new LinkedHashMap<String, Service>(256);
                     }
-                    propertyAliasTable.put(serviceName, aliasName.toUpperCase(Locale.US), s);
+                    propertyAliasTable.put(key(serviceName, aliasName), s);
                 } else {
                     String className = (String) changedProperties
                             .get(serviceName + "." + algorithm);
@@ -689,11 +691,11 @@
                         l.add(aliasName);
                         s = new Provider.Service(this, serviceName, algorithm,
                                 className, l, new HashMap<String, String>());
-                        propertyServiceTable.put(serviceName, algUp, s);
+                        propertyServiceTable.put(propertyServiceTableKey, s);
                         if (propertyAliasTable == null) {
-                            propertyAliasTable = new TwoKeyHashMap<String, String, Service>(256);
+                            propertyAliasTable = new LinkedHashMap<String, Service>(256);
                         }
-                        propertyAliasTable.put(serviceName, aliasName.toUpperCase(Locale.US), s);
+                        propertyAliasTable.put(key(serviceName, aliasName), s);
                     }
                 }
                 continue;
@@ -706,10 +708,10 @@
             if (i == -1) { // <crypto_service>.<algorithm_or_type>=<className>
                 serviceName = key.substring(0, j);
                 algorithm = key.substring(j + 1);
-                String alg = algorithm.toUpperCase(Locale.US);
+                String propertyServiceTableKey = key(serviceName, algorithm);
                 Object o = null;
                 if (propertyServiceTable != null) {
-                    o = propertyServiceTable.get(serviceName, alg);
+                    o = propertyServiceTable.get(propertyServiceTableKey);
                 }
                 if (o != null) {
                     s = (Provider.Service) o;
@@ -719,21 +721,20 @@
                             value, Collections.<String>emptyList(),
                             Collections.<String,String>emptyMap());
                     if (propertyServiceTable == null) {
-                        propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+                        propertyServiceTable = new LinkedHashMap<String, Service>(128);
                     }
-                    propertyServiceTable.put(serviceName, alg, s);
+                    propertyServiceTable.put(propertyServiceTableKey, s);
 
                 }
             } else {
-                // <crypto_service>.<algorithm_or_type>
-                // <attribute_name>=<attrValue>
+                // <crypto_service>.<algorithm_or_type> <attribute_name>=<attrValue>
                 serviceName = key.substring(0, j);
                 algorithm = key.substring(j + 1, i);
                 String attribute = key.substring(i + 1);
-                String alg = algorithm.toUpperCase(Locale.US);
+                String propertyServiceTableKey = key(serviceName, algorithm);
                 Object o = null;
                 if (propertyServiceTable != null) {
-                    o = propertyServiceTable.get(serviceName, alg);
+                    o = propertyServiceTable.get(propertyServiceTableKey);
                 }
                 if (o != null) {
                     s = (Provider.Service) o;
@@ -747,9 +748,9 @@
                         s = new Provider.Service(this, serviceName, algorithm,
                                 className, new ArrayList<String>(), m);
                         if (propertyServiceTable == null) {
-                            propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+                            propertyServiceTable = new LinkedHashMap<String, Service>(128);
                         }
-                        propertyServiceTable.put(serviceName, alg, s);
+                        propertyServiceTable.put(propertyServiceTableKey, s);
                     }
                 }
             }
@@ -794,6 +795,10 @@
         return null;
     }
 
+    private static String key(String type, String algorithm) {
+        return type + '.' + algorithm.toUpperCase(Locale.US);
+    }
+
     /**
      * {@code Service} represents a service in the Java Security infrastructure.
      * Each service describes its type, the algorithm it implements, to which
@@ -849,9 +854,14 @@
          */
         public Service(Provider provider, String type, String algorithm,
                 String className, List<String> aliases, Map<String, String> attributes) {
-            if (provider == null || type == null || algorithm == null
-                    || className == null) {
-                throw new NullPointerException();
+            if (provider == null) {
+                throw new NullPointerException("provider == null");
+            } else if (type == null) {
+                throw new NullPointerException("type == null");
+            } else if (algorithm == null) {
+                throw new NullPointerException("algorithm == null");
+            } else if (className == null) {
+                throw new NullPointerException("className == null");
             }
             this.provider = provider;
             this.type = type;
@@ -940,7 +950,7 @@
          */
         public final String getAttribute(String name) {
             if (name == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("name == null");
             }
             if (attributes == null) {
                 return null;
diff --git a/luni/src/main/java/java/security/SecureRandom.java b/luni/src/main/java/java/security/SecureRandom.java
index 68a2917..6ed631c 100644
--- a/luni/src/main/java/java/security/SecureRandom.java
+++ b/luni/src/main/java/java/security/SecureRandom.java
@@ -88,7 +88,6 @@
      */
     public SecureRandom() {
         super(0);
-        Services.refresh();
         Provider.Service service = Services.getSecureRandomService();
         if (service == null) {
             this.provider = null;
@@ -154,7 +153,7 @@
      */
     public static SecureRandom getInstance(String algorithm) throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new SecureRandom((SecureRandomSpi) sap.spi, sap.provider,
@@ -213,7 +212,7 @@
             throw new IllegalArgumentException();
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new SecureRandom((SecureRandomSpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/java/security/Security.java b/luni/src/main/java/java/security/Security.java
index a4cc6e1..b5bd02a 100644
--- a/luni/src/main/java/java/security/Security.java
+++ b/luni/src/main/java/java/security/Security.java
@@ -227,7 +227,7 @@
      */
     public static Provider[] getProviders(String filter) {
         if (filter == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("filter == null");
         }
         if (filter.length() == 0) {
             throw new InvalidParameterException();
@@ -271,7 +271,7 @@
      */
     public static synchronized Provider[] getProviders(Map<String,String> filter) {
         if (filter == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("filter == null");
         }
         if (filter.isEmpty()) {
             return null;
diff --git a/luni/src/main/java/java/security/Signature.java b/luni/src/main/java/java/security/Signature.java
index d9e1e41..be89654 100644
--- a/luni/src/main/java/java/security/Signature.java
+++ b/luni/src/main/java/java/security/Signature.java
@@ -99,7 +99,7 @@
     public static Signature getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         Object spi = sap.spi;
@@ -134,7 +134,7 @@
     public static Signature getInstance(String algorithm, String provider)
             throws NoSuchAlgorithmException, NoSuchProviderException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         if (provider == null || provider.isEmpty()) {
             throw new IllegalArgumentException();
@@ -165,7 +165,7 @@
     public static Signature getInstance(String algorithm, Provider provider)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         if (provider == null) {
             throw new IllegalArgumentException();
diff --git a/luni/src/main/java/java/security/Signer.java b/luni/src/main/java/java/security/Signer.java
index 1e4412a..b892090 100644
--- a/luni/src/main/java/java/security/Signer.java
+++ b/luni/src/main/java/java/security/Signer.java
@@ -83,7 +83,7 @@
      */
     public final void setKeyPair(KeyPair pair) throws InvalidParameterException, KeyException {
         if (pair == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("pair == null");
         }
 
         if (pair.getPrivate() == null || pair.getPublic() == null) {
diff --git a/luni/src/main/java/java/security/cert/CertPathBuilder.java b/luni/src/main/java/java/security/cert/CertPathBuilder.java
index aa65fe7..42029e5 100644
--- a/luni/src/main/java/java/security/cert/CertPathBuilder.java
+++ b/luni/src/main/java/java/security/cert/CertPathBuilder.java
@@ -102,7 +102,7 @@
     public static CertPathBuilder getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new CertPathBuilder((CertPathBuilderSpi) sap.spi, sap.provider, algorithm);
@@ -128,7 +128,7 @@
     public static CertPathBuilder getInstance(String algorithm, String provider)
             throws NoSuchAlgorithmException, NoSuchProviderException {
         if (provider == null || provider.isEmpty()) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("provider == null || provider.isEmpty()");
         }
         Provider impProvider = Security.getProvider(provider);
         if (impProvider == null) {
@@ -156,10 +156,10 @@
     public static CertPathBuilder getInstance(String algorithm,
             Provider provider) throws NoSuchAlgorithmException {
         if (provider == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("provider == null");
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new CertPathBuilder((CertPathBuilderSpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/java/security/cert/CertPathValidator.java b/luni/src/main/java/java/security/cert/CertPathValidator.java
index 69b9f99..ddf78bf 100644
--- a/luni/src/main/java/java/security/cert/CertPathValidator.java
+++ b/luni/src/main/java/java/security/cert/CertPathValidator.java
@@ -101,7 +101,7 @@
     public static CertPathValidator getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new CertPathValidator((CertPathValidatorSpi) sap.spi, sap.provider, algorithm);
@@ -160,7 +160,7 @@
             throw new IllegalArgumentException();
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new CertPathValidator((CertPathValidatorSpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/java/security/cert/CertStore.java b/luni/src/main/java/java/security/cert/CertStore.java
index 6cdaea7..2e28828 100644
--- a/luni/src/main/java/java/security/cert/CertStore.java
+++ b/luni/src/main/java/java/security/cert/CertStore.java
@@ -97,7 +97,7 @@
     public static CertStore getInstance(String type, CertStoreParameters params)
             throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
         if (type == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("type == null");
         }
         try {
             Engine.SpiAndProvider sap = ENGINE.getInstance(type, params);
@@ -140,7 +140,7 @@
             throws InvalidAlgorithmParameterException,
             NoSuchAlgorithmException, NoSuchProviderException {
         if (provider == null || provider.isEmpty()) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("provider == null || provider.isEmpty()");
         }
         Provider impProvider = Security.getProvider(provider);
         if (impProvider == null) {
@@ -172,10 +172,10 @@
             CertStoreParameters params, Provider provider)
             throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
         if (provider == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("provider == null");
         }
         if (type == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("type == null");
         }
         try {
             Object spi = ENGINE.getInstance(type, provider, params);
diff --git a/luni/src/main/java/java/security/cert/CertificateFactory.java b/luni/src/main/java/java/security/cert/CertificateFactory.java
index 1aac1a0..83d40d3 100644
--- a/luni/src/main/java/java/security/cert/CertificateFactory.java
+++ b/luni/src/main/java/java/security/cert/CertificateFactory.java
@@ -84,7 +84,7 @@
     public static final CertificateFactory getInstance(String type)
             throws CertificateException {
         if (type == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("type == null");
         }
         try {
             Engine.SpiAndProvider sap = ENGINE.getInstance(type, null);
@@ -117,7 +117,7 @@
             String provider) throws CertificateException,
             NoSuchProviderException {
         if (provider == null || provider.isEmpty()) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("provider == null || provider.isEmpty()");
         }
         Provider impProvider = Security.getProvider(provider);
         if (impProvider == null) {
@@ -147,10 +147,10 @@
     public static final CertificateFactory getInstance(String type,
             Provider provider) throws CertificateException {
         if (provider == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("provider == null");
         }
         if (type == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("type == null");
         }
         try {
             Object spi = ENGINE.getInstance(type, provider, null);
diff --git a/luni/src/main/java/java/security/cert/CollectionCertStoreParameters.java b/luni/src/main/java/java/security/cert/CollectionCertStoreParameters.java
index de3c85d..9373b40 100644
--- a/luni/src/main/java/java/security/cert/CollectionCertStoreParameters.java
+++ b/luni/src/main/java/java/security/cert/CollectionCertStoreParameters.java
@@ -58,10 +58,10 @@
      *             if {@code collection is null}.
      */
     public CollectionCertStoreParameters(Collection<?> collection) {
-        this.collection = collection;
-        if (this.collection == null) {
-            throw new NullPointerException();
+        if (collection == null) {
+            throw new NullPointerException("collection == null");
         }
+        this.collection = collection;
     }
 
     /**
diff --git a/luni/src/main/java/java/security/cert/LDAPCertStoreParameters.java b/luni/src/main/java/java/security/cert/LDAPCertStoreParameters.java
index 5b01f90..163c99a 100644
--- a/luni/src/main/java/java/security/cert/LDAPCertStoreParameters.java
+++ b/luni/src/main/java/java/security/cert/LDAPCertStoreParameters.java
@@ -43,11 +43,11 @@
      *             is {@code serverName} is {@code null}.
      */
     public LDAPCertStoreParameters(String serverName, int port) {
+        if (serverName == null) {
+            throw new NullPointerException("serverName == null");
+        }
         this.port = port;
         this.serverName = serverName;
-        if (this.serverName == null) {
-            throw new NullPointerException();
-        }
     }
 
     /**
@@ -71,11 +71,11 @@
      *             if {@code serverName} is {@code null}.
      */
     public LDAPCertStoreParameters(String serverName) {
+        if (serverName == null) {
+            throw new NullPointerException("serverName == null");
+        }
         this.port = DEFAULT_LDAP_PORT;
         this.serverName = serverName;
-        if (this.serverName == null) {
-            throw new NullPointerException();
-        }
     }
 
     /**
diff --git a/luni/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java b/luni/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java
index 589ce82..2359612 100644
--- a/luni/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java
+++ b/luni/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java
@@ -49,10 +49,10 @@
     public PKIXCertPathBuilderResult(CertPath certPath, TrustAnchor trustAnchor,
             PolicyNode policyTree, PublicKey subjectPublicKey) {
         super(trustAnchor, policyTree, subjectPublicKey);
-        this.certPath = certPath;
-        if (this.certPath == null) {
+        if (certPath == null) {
             throw new NullPointerException("certPath == null");
         }
+        this.certPath = certPath;
     }
 
     /**
diff --git a/luni/src/main/java/java/security/cert/X509CRL.java b/luni/src/main/java/java/security/cert/X509CRL.java
index 4badd59..4addb0e 100644
--- a/luni/src/main/java/java/security/cert/X509CRL.java
+++ b/luni/src/main/java/java/security/cert/X509CRL.java
@@ -218,7 +218,7 @@
      */
     public X509CRLEntry getRevokedCertificate(X509Certificate certificate) {
         if (certificate == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("certificate == null");
         }
         return getRevokedCertificate(certificate.getSerialNumber());
     }
diff --git a/luni/src/main/java/java/security/spec/ECGenParameterSpec.java b/luni/src/main/java/java/security/spec/ECGenParameterSpec.java
index fe66b1e..c22038d 100644
--- a/luni/src/main/java/java/security/spec/ECGenParameterSpec.java
+++ b/luni/src/main/java/java/security/spec/ECGenParameterSpec.java
@@ -35,7 +35,7 @@
     public ECGenParameterSpec(String name) {
         this.name = name;
         if (this.name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
     }
 
diff --git a/luni/src/main/java/java/sql/DataTruncation.java b/luni/src/main/java/java/sql/DataTruncation.java
index b01100e..c1bf11c 100644
--- a/luni/src/main/java/java/sql/DataTruncation.java
+++ b/luni/src/main/java/java/sql/DataTruncation.java
@@ -49,7 +49,7 @@
 
     /**
      * Creates the {@code DataTruncation} object. The reason is set to {@code
-     * "Data truncation"}, the {@code ErrorCode} is set to the {@code
+     * "Data truncation"}, the error code is set to the {@code
      * SQLException} default value, and the other fields are set to the values
      * supplied as arguments.
      *
@@ -79,7 +79,7 @@
 
     /**
      * Creates a DataTruncation. The Reason is set to "Data truncation", the
-     * ErrorCode is set to the SQLException default value and other fields are
+     * error code is set to the SQLException default value and other fields are
      * set to the values supplied on this method.
      *
      * @param index
diff --git a/luni/src/main/java/java/sql/DriverManager.java b/luni/src/main/java/java/sql/DriverManager.java
index 4cee1fe..c547585 100644
--- a/luni/src/main/java/java/sql/DriverManager.java
+++ b/luni/src/main/java/java/sql/DriverManager.java
@@ -329,7 +329,7 @@
      */
     public static void registerDriver(Driver driver) throws SQLException {
         if (driver == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("driver == null");
         }
         synchronized (theDrivers) {
             theDrivers.add(driver);
diff --git a/luni/src/main/java/java/text/AttributedString.java b/luni/src/main/java/java/text/AttributedString.java
index 1335067..d679283 100644
--- a/luni/src/main/java/java/text/AttributedString.java
+++ b/luni/src/main/java/java/text/AttributedString.java
@@ -519,7 +519,7 @@
      */
     public AttributedString(String value) {
         if (value == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("value == null");
         }
         text = value;
         attributeMap = new HashMap<Attribute, List<Range>>(11);
@@ -542,7 +542,7 @@
     public AttributedString(String value,
             Map<? extends AttributedCharacterIterator.Attribute, ?> attributes) {
         if (value == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("value == null");
         }
         if (value.length() == 0 && !attributes.isEmpty()) {
             throw new IllegalArgumentException("Cannot add attributes to empty string");
@@ -575,7 +575,7 @@
      */
     public void addAttribute(AttributedCharacterIterator.Attribute attribute, Object value) {
         if (attribute == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("attribute == null");
         }
         if (text.length() == 0) {
             throw new IllegalArgumentException();
@@ -612,7 +612,7 @@
     public void addAttribute(AttributedCharacterIterator.Attribute attribute,
             Object value, int start, int end) {
         if (attribute == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("attribute == null");
         }
         if (start < 0 || end > text.length() || start >= end) {
             throw new IllegalArgumentException();
diff --git a/luni/src/main/java/java/text/Collator.java b/luni/src/main/java/java/text/Collator.java
index 0fa8c71..2ddb516 100644
--- a/luni/src/main/java/java/text/Collator.java
+++ b/luni/src/main/java/java/text/Collator.java
@@ -286,7 +286,7 @@
      */
     public static Collator getInstance(Locale locale) {
         if (locale == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("locale == null");
         }
         return new RuleBasedCollator(new RuleBasedCollatorICU(locale));
     }
diff --git a/luni/src/main/java/java/text/DateFormat.java b/luni/src/main/java/java/text/DateFormat.java
index 4055d20..b45e699 100644
--- a/luni/src/main/java/java/text/DateFormat.java
+++ b/luni/src/main/java/java/text/DateFormat.java
@@ -286,10 +286,6 @@
 
     /**
      * Returns a new instance of {@code DateFormat} with the same properties.
-     *
-     * @return a shallow copy of this {@code DateFormat}.
-     *
-     * @see java.lang.Cloneable
      */
     @Override
     public Object clone() {
diff --git a/luni/src/main/java/java/text/DateFormatSymbols.java b/luni/src/main/java/java/text/DateFormatSymbols.java
index 3c4768d..e2a2345 100644
--- a/luni/src/main/java/java/text/DateFormatSymbols.java
+++ b/luni/src/main/java/java/text/DateFormatSymbols.java
@@ -142,7 +142,7 @@
      */
     public static final DateFormatSymbols getInstance(Locale locale) {
         if (locale == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("locale == null");
         }
         return new DateFormatSymbols(locale);
     }
@@ -410,7 +410,7 @@
      */
     public void setLocalPatternChars(String data) {
         if (data == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("data == null");
         }
         localPatternChars = data;
     }
@@ -471,7 +471,7 @@
      */
     public void setZoneStrings(String[][] zoneStrings) {
         if (zoneStrings == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("zoneStrings == null");
         }
         for (String[] row : zoneStrings) {
             if (row.length < 5) {
diff --git a/luni/src/main/java/java/text/DecimalFormat.java b/luni/src/main/java/java/text/DecimalFormat.java
index c1a48db..948bec1 100644
--- a/luni/src/main/java/java/text/DecimalFormat.java
+++ b/luni/src/main/java/java/text/DecimalFormat.java
@@ -501,16 +501,7 @@
 
     private transient DecimalFormatSymbols symbols;
 
-    private transient NativeDecimalFormat dform;
-    private final Object finalizerGuardian = new Object() {
-        @Override protected void finalize() throws Throwable {
-            try {
-                dform.close();
-            } finally {
-                super.finalize();
-            }
-        }
-    };
+    private transient NativeDecimalFormat ndf;
 
     private transient RoundingMode roundingMode = RoundingMode.HALF_EVEN;
 
@@ -562,14 +553,14 @@
 
     private void initNative(String pattern) {
         try {
-            this.dform = new NativeDecimalFormat(pattern, symbols);
+            this.ndf = new NativeDecimalFormat(pattern, symbols);
         } catch (IllegalArgumentException ex) {
             throw new IllegalArgumentException(pattern);
         }
-        super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
-        super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
-        super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
-        super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
+        super.setMaximumFractionDigits(ndf.getMaximumFractionDigits());
+        super.setMaximumIntegerDigits(ndf.getMaximumIntegerDigits());
+        super.setMinimumFractionDigits(ndf.getMinimumFractionDigits());
+        super.setMinimumIntegerDigits(ndf.getMinimumIntegerDigits());
     }
 
     /**
@@ -582,7 +573,7 @@
      *            if the pattern cannot be parsed.
      */
     public void applyLocalizedPattern(String pattern) {
-        dform.applyLocalizedPattern(pattern);
+        ndf.applyLocalizedPattern(pattern);
     }
 
     /**
@@ -595,20 +586,17 @@
      *            if the pattern cannot be parsed.
      */
     public void applyPattern(String pattern) {
-        dform.applyPattern(pattern);
+        ndf.applyPattern(pattern);
     }
 
     /**
      * Returns a new instance of {@code DecimalFormat} with the same pattern and
-     * properties as this decimal format.
-     *
-     * @return a shallow copy of this decimal format.
-     * @see java.lang.Cloneable
+     * properties.
      */
     @Override
     public Object clone() {
         DecimalFormat clone = (DecimalFormat) super.clone();
-        clone.dform = (NativeDecimalFormat) dform.clone();
+        clone.ndf = (NativeDecimalFormat) ndf.clone();
         clone.symbols = (DecimalFormatSymbols) symbols.clone();
         return clone;
     }
@@ -633,7 +621,7 @@
             return false;
         }
         DecimalFormat other = (DecimalFormat) object;
-        return (this.dform == null ? other.dform == null : this.dform.equals(other.dform)) &&
+        return (this.ndf == null ? other.ndf == null : this.ndf.equals(other.ndf)) &&
                 getDecimalFormatSymbols().equals(other.getDecimalFormatSymbols());
     }
 
@@ -654,9 +642,9 @@
     @Override
     public AttributedCharacterIterator formatToCharacterIterator(Object object) {
         if (object == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("object == null");
         }
-        return dform.formatToCharacterIterator(object);
+        return ndf.formatToCharacterIterator(object);
     }
 
     private void checkBufferAndFieldPosition(StringBuffer buffer, FieldPosition position) {
@@ -686,14 +674,14 @@
                 setRoundingMode(RoundingMode.UNNECESSARY);
             }
         }
-        buffer.append(dform.formatDouble(value, position));
+        buffer.append(ndf.formatDouble(value, position));
         return buffer;
     }
 
     @Override
     public StringBuffer format(long value, StringBuffer buffer, FieldPosition position) {
         checkBufferAndFieldPosition(buffer, position);
-        buffer.append(dform.formatLong(value, position));
+        buffer.append(ndf.formatLong(value, position));
         return buffer;
     }
 
@@ -703,12 +691,12 @@
         if (number instanceof BigInteger) {
             BigInteger bigInteger = (BigInteger) number;
             char[] chars = (bigInteger.bitLength() < 64)
-                    ? dform.formatLong(bigInteger.longValue(), position)
-                    : dform.formatBigInteger(bigInteger, position);
+                    ? ndf.formatLong(bigInteger.longValue(), position)
+                    : ndf.formatBigInteger(bigInteger, position);
             buffer.append(chars);
             return buffer;
         } else if (number instanceof BigDecimal) {
-            buffer.append(dform.formatBigDecimal((BigDecimal) number, position));
+            buffer.append(ndf.formatBigDecimal((BigDecimal) number, position));
             return buffer;
         }
         return super.format(number, buffer, position);
@@ -743,7 +731,7 @@
      * @return the number of digits grouped together.
      */
     public int getGroupingSize() {
-        return dform.getGroupingSize();
+        return ndf.getGroupingSize();
     }
 
     /**
@@ -753,7 +741,7 @@
      * @return the multiplier.
      */
     public int getMultiplier() {
-        return dform.getMultiplier();
+        return ndf.getMultiplier();
     }
 
     /**
@@ -762,7 +750,7 @@
      * @return the negative prefix.
      */
     public String getNegativePrefix() {
-        return dform.getNegativePrefix();
+        return ndf.getNegativePrefix();
     }
 
     /**
@@ -771,7 +759,7 @@
      * @return the negative suffix.
      */
     public String getNegativeSuffix() {
-        return dform.getNegativeSuffix();
+        return ndf.getNegativeSuffix();
     }
 
     /**
@@ -780,7 +768,7 @@
      * @return the positive prefix.
      */
     public String getPositivePrefix() {
-        return dform.getPositivePrefix();
+        return ndf.getPositivePrefix();
     }
 
     /**
@@ -789,12 +777,12 @@
      * @return the positive suffix.
      */
     public String getPositiveSuffix() {
-        return dform.getPositiveSuffix();
+        return ndf.getPositiveSuffix();
     }
 
     @Override
     public int hashCode() {
-        return dform.hashCode();
+        return getPositivePrefix().hashCode();
     }
 
     /**
@@ -805,7 +793,7 @@
      *         {@code false} otherwise.
      */
     public boolean isDecimalSeparatorAlwaysShown() {
-        return dform.isDecimalSeparatorAlwaysShown();
+        return ndf.isDecimalSeparatorAlwaysShown();
     }
 
     /**
@@ -817,7 +805,7 @@
      *         {@code Double}.
      */
     public boolean isParseBigDecimal() {
-        return dform.isParseBigDecimal();
+        return ndf.isParseBigDecimal();
     }
 
     /**
@@ -838,7 +826,7 @@
         // In this implementation, NativeDecimalFormat is wrapped to
         // fulfill most of the format and parse feature. And this method is
         // delegated to the wrapped instance of NativeDecimalFormat.
-        dform.setParseIntegerOnly(value);
+        ndf.setParseIntegerOnly(value);
     }
 
     /**
@@ -850,7 +838,7 @@
      */
     @Override
     public boolean isParseIntegerOnly() {
-        return dform.isParseIntegerOnly();
+        return ndf.isParseIntegerOnly();
     }
 
     private static final Double NEGATIVE_ZERO_DOUBLE = new Double(-0.0);
@@ -880,7 +868,7 @@
      */
     @Override
     public Number parse(String string, ParsePosition position) {
-        Number number = dform.parse(string, position);
+        Number number = ndf.parse(string, position);
         if (number == null) {
             return null;
         }
@@ -918,7 +906,7 @@
         if (value != null) {
             // The Java object is canonical, and we copy down to native code.
             this.symbols = (DecimalFormatSymbols) value.clone();
-            dform.setDecimalFormatSymbols(this.symbols);
+            ndf.setDecimalFormatSymbols(this.symbols);
         }
     }
 
@@ -932,7 +920,7 @@
      */
     @Override
     public void setCurrency(Currency currency) {
-        dform.setCurrency(Currency.getInstance(currency.getCurrencyCode()));
+        ndf.setCurrency(Currency.getInstance(currency.getCurrencyCode()));
         symbols.setCurrency(currency);
     }
 
@@ -945,7 +933,7 @@
      *            formatted; {@code false} otherwise.
      */
     public void setDecimalSeparatorAlwaysShown(boolean value) {
-        dform.setDecimalSeparatorAlwaysShown(value);
+        ndf.setDecimalSeparatorAlwaysShown(value);
     }
 
     /**
@@ -957,7 +945,7 @@
      *            the number of digits grouped together.
      */
     public void setGroupingSize(int value) {
-        dform.setGroupingSize(value);
+        ndf.setGroupingSize(value);
     }
 
     /**
@@ -969,7 +957,7 @@
      */
     @Override
     public void setGroupingUsed(boolean value) {
-        dform.setGroupingUsed(value);
+        ndf.setGroupingUsed(value);
     }
 
     /**
@@ -979,7 +967,7 @@
      */
     @Override
     public boolean isGroupingUsed() {
-        return dform.isGroupingUsed();
+        return ndf.isGroupingUsed();
     }
 
     /**
@@ -992,7 +980,7 @@
     @Override
     public void setMaximumFractionDigits(int value) {
         super.setMaximumFractionDigits(value);
-        dform.setMaximumFractionDigits(getMaximumFractionDigits());
+        ndf.setMaximumFractionDigits(getMaximumFractionDigits());
         // Changing the maximum fraction digits needs to update ICU4C's rounding configuration.
         setRoundingMode(roundingMode);
     }
@@ -1007,7 +995,7 @@
     @Override
     public void setMaximumIntegerDigits(int value) {
         super.setMaximumIntegerDigits(value);
-        dform.setMaximumIntegerDigits(getMaximumIntegerDigits());
+        ndf.setMaximumIntegerDigits(getMaximumIntegerDigits());
     }
 
     /**
@@ -1020,7 +1008,7 @@
     @Override
     public void setMinimumFractionDigits(int value) {
         super.setMinimumFractionDigits(value);
-        dform.setMinimumFractionDigits(getMinimumFractionDigits());
+        ndf.setMinimumFractionDigits(getMinimumFractionDigits());
     }
 
     /**
@@ -1033,7 +1021,7 @@
     @Override
     public void setMinimumIntegerDigits(int value) {
         super.setMinimumIntegerDigits(value);
-        dform.setMinimumIntegerDigits(getMinimumIntegerDigits());
+        ndf.setMinimumIntegerDigits(getMinimumIntegerDigits());
     }
 
     /**
@@ -1044,7 +1032,7 @@
      *            the multiplier.
      */
     public void setMultiplier(int value) {
-        dform.setMultiplier(value);
+        ndf.setMultiplier(value);
     }
 
     /**
@@ -1054,7 +1042,7 @@
      *            the negative prefix.
      */
     public void setNegativePrefix(String value) {
-        dform.setNegativePrefix(value);
+        ndf.setNegativePrefix(value);
     }
 
     /**
@@ -1064,7 +1052,7 @@
      *            the negative suffix.
      */
     public void setNegativeSuffix(String value) {
-        dform.setNegativeSuffix(value);
+        ndf.setNegativeSuffix(value);
     }
 
     /**
@@ -1074,7 +1062,7 @@
      *            the positive prefix.
      */
     public void setPositivePrefix(String value) {
-        dform.setPositivePrefix(value);
+        ndf.setPositivePrefix(value);
     }
 
     /**
@@ -1084,7 +1072,7 @@
      *            the positive suffix.
      */
     public void setPositiveSuffix(String value) {
-        dform.setPositiveSuffix(value);
+        ndf.setPositiveSuffix(value);
     }
 
     /**
@@ -1096,7 +1084,7 @@
      *            {@code BigDecimal}; {@code false} otherwise.
      */
     public void setParseBigDecimal(boolean newValue) {
-        dform.setParseBigDecimal(newValue);
+        ndf.setParseBigDecimal(newValue);
     }
 
     /**
@@ -1106,7 +1094,7 @@
      * @return the localized pattern.
      */
     public String toLocalizedPattern() {
-        return dform.toLocalizedPattern();
+        return ndf.toLocalizedPattern();
     }
 
     /**
@@ -1116,7 +1104,7 @@
      * @return the non-localized pattern.
      */
     public String toPattern() {
-        return dform.toPattern();
+        return ndf.toPattern();
     }
 
     // the fields list to be serialized
@@ -1157,27 +1145,27 @@
      */
     private void writeObject(ObjectOutputStream stream) throws IOException, ClassNotFoundException {
         ObjectOutputStream.PutField fields = stream.putFields();
-        fields.put("positivePrefix", dform.getPositivePrefix());
-        fields.put("positiveSuffix", dform.getPositiveSuffix());
-        fields.put("negativePrefix", dform.getNegativePrefix());
-        fields.put("negativeSuffix", dform.getNegativeSuffix());
+        fields.put("positivePrefix", ndf.getPositivePrefix());
+        fields.put("positiveSuffix", ndf.getPositiveSuffix());
+        fields.put("negativePrefix", ndf.getNegativePrefix());
+        fields.put("negativeSuffix", ndf.getNegativeSuffix());
         fields.put("posPrefixPattern", (String) null);
         fields.put("posSuffixPattern", (String) null);
         fields.put("negPrefixPattern", (String) null);
         fields.put("negSuffixPattern", (String) null);
-        fields.put("multiplier", dform.getMultiplier());
-        fields.put("groupingSize", (byte) dform.getGroupingSize());
-        fields.put("groupingUsed", dform.isGroupingUsed());
-        fields.put("decimalSeparatorAlwaysShown", dform.isDecimalSeparatorAlwaysShown());
-        fields.put("parseBigDecimal", dform.isParseBigDecimal());
+        fields.put("multiplier", ndf.getMultiplier());
+        fields.put("groupingSize", (byte) ndf.getGroupingSize());
+        fields.put("groupingUsed", ndf.isGroupingUsed());
+        fields.put("decimalSeparatorAlwaysShown", ndf.isDecimalSeparatorAlwaysShown());
+        fields.put("parseBigDecimal", ndf.isParseBigDecimal());
         fields.put("roundingMode", roundingMode);
         fields.put("symbols", symbols);
         fields.put("useExponentialNotation", false);
         fields.put("minExponentDigits", (byte) 0);
-        fields.put("maximumIntegerDigits", dform.getMaximumIntegerDigits());
-        fields.put("minimumIntegerDigits", dform.getMinimumIntegerDigits());
-        fields.put("maximumFractionDigits", dform.getMaximumFractionDigits());
-        fields.put("minimumFractionDigits", dform.getMinimumFractionDigits());
+        fields.put("maximumIntegerDigits", ndf.getMaximumIntegerDigits());
+        fields.put("minimumIntegerDigits", ndf.getMinimumIntegerDigits());
+        fields.put("maximumFractionDigits", ndf.getMaximumFractionDigits());
+        fields.put("minimumFractionDigits", ndf.getMinimumFractionDigits());
         fields.put("serialVersionOnStream", 4);
         stream.writeFields();
     }
@@ -1198,14 +1186,14 @@
         this.symbols = (DecimalFormatSymbols) fields.get("symbols", null);
 
         initNative("");
-        dform.setPositivePrefix((String) fields.get("positivePrefix", ""));
-        dform.setPositiveSuffix((String) fields.get("positiveSuffix", ""));
-        dform.setNegativePrefix((String) fields.get("negativePrefix", "-"));
-        dform.setNegativeSuffix((String) fields.get("negativeSuffix", ""));
-        dform.setMultiplier(fields.get("multiplier", 1));
-        dform.setGroupingSize(fields.get("groupingSize", (byte) 3));
-        dform.setGroupingUsed(fields.get("groupingUsed", true));
-        dform.setDecimalSeparatorAlwaysShown(fields.get("decimalSeparatorAlwaysShown", false));
+        ndf.setPositivePrefix((String) fields.get("positivePrefix", ""));
+        ndf.setPositiveSuffix((String) fields.get("positiveSuffix", ""));
+        ndf.setNegativePrefix((String) fields.get("negativePrefix", "-"));
+        ndf.setNegativeSuffix((String) fields.get("negativeSuffix", ""));
+        ndf.setMultiplier(fields.get("multiplier", 1));
+        ndf.setGroupingSize(fields.get("groupingSize", (byte) 3));
+        ndf.setGroupingUsed(fields.get("groupingUsed", true));
+        ndf.setDecimalSeparatorAlwaysShown(fields.get("decimalSeparatorAlwaysShown", false));
 
         setRoundingMode((RoundingMode) fields.get("roundingMode", RoundingMode.HALF_EVEN));
 
@@ -1218,8 +1206,8 @@
         // behavior in this area is, and it's not obvious how we can second-guess ICU (or tell
         // it to just do exactly what we ask). We only need to do this with maximumIntegerDigits
         // because ICU doesn't seem to have its own ideas about the other options.
-        dform.setMaximumIntegerDigits(maximumIntegerDigits);
-        super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
+        ndf.setMaximumIntegerDigits(maximumIntegerDigits);
+        super.setMaximumIntegerDigits(ndf.getMaximumIntegerDigits());
 
         setMinimumIntegerDigits(minimumIntegerDigits);
         setMinimumFractionDigits(minimumFractionDigits);
@@ -1248,12 +1236,12 @@
      */
     public void setRoundingMode(RoundingMode roundingMode) {
         if (roundingMode == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("roundingMode == null");
         }
         this.roundingMode = roundingMode;
         if (roundingMode != RoundingMode.UNNECESSARY) { // ICU4C doesn't support UNNECESSARY.
             double roundingIncrement = 1.0 / Math.pow(10, Math.max(0, getMaximumFractionDigits()));
-            dform.setRoundingMode(roundingMode, roundingIncrement);
+            ndf.setRoundingMode(roundingMode, roundingIncrement);
         }
     }
 }
diff --git a/luni/src/main/java/java/text/DecimalFormatSymbols.java b/luni/src/main/java/java/text/DecimalFormatSymbols.java
index 9d2bcc1..708b291 100644
--- a/luni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/luni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -127,7 +127,7 @@
      */
     public static DecimalFormatSymbols getInstance(Locale locale) {
         if (locale == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("locale == null");
         }
         return new DecimalFormatSymbols(locale);
     }
@@ -389,7 +389,7 @@
      */
     public void setCurrency(Currency currency) {
         if (currency == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("currency == null");
         }
         if (currency == this.currency) {
             return;
@@ -558,7 +558,7 @@
      */
     public void setExponentSeparator(String value) {
         if (value == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("value == null");
         }
         this.exponentSeparator = value;
     }
diff --git a/luni/src/main/java/java/text/MessageFormat.java b/luni/src/main/java/java/text/MessageFormat.java
index a98e4fd..2ab78db 100644
--- a/luni/src/main/java/java/text/MessageFormat.java
+++ b/luni/src/main/java/java/text/MessageFormat.java
@@ -506,7 +506,7 @@
     @Override
     public AttributedCharacterIterator formatToCharacterIterator(Object object) {
         if (object == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("object == null");
         }
 
         StringBuffer buffer = new StringBuffer();
diff --git a/luni/src/main/java/java/text/NumberFormat.java b/luni/src/main/java/java/text/NumberFormat.java
index 3bff6ad..c285e3d 100644
--- a/luni/src/main/java/java/text/NumberFormat.java
+++ b/luni/src/main/java/java/text/NumberFormat.java
@@ -165,11 +165,7 @@
     }
 
     /**
-     * Returns a new {@code NumberFormat} with the same properties as this
-     * {@code NumberFormat}.
-     *
-     * @return a shallow copy of this {@code NumberFormat}.
-     * @see java.lang.Cloneable
+     * Returns a new {@code NumberFormat} with the same properties.
      */
     @Override
     public Object clone() {
@@ -570,7 +566,7 @@
     @Override
     public final Object parseObject(String string, ParsePosition position) {
         if (position == null) {
-            throw new NullPointerException("position is null");
+            throw new NullPointerException("position == null");
         }
         try {
             return parse(string, position);
diff --git a/luni/src/main/java/java/text/RuleBasedCollator.java b/luni/src/main/java/java/text/RuleBasedCollator.java
index 4fd8650..cda06db 100644
--- a/luni/src/main/java/java/text/RuleBasedCollator.java
+++ b/luni/src/main/java/java/text/RuleBasedCollator.java
@@ -284,7 +284,7 @@
      */
     public RuleBasedCollator(String rules) throws ParseException {
         if (rules == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("rules == null");
         }
         if (rules.isEmpty()) {
             throw new ParseException("empty rules", 0);
@@ -314,7 +314,7 @@
      */
     public CollationElementIterator getCollationElementIterator(CharacterIterator source) {
         if (source == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("source == null");
         }
         return new CollationElementIterator(icuColl.getCollationElementIterator(source));
     }
@@ -328,7 +328,7 @@
      */
     public CollationElementIterator getCollationElementIterator(String source) {
         if (source == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("source == null");
         }
         return new CollationElementIterator(icuColl.getCollationElementIterator(source));
     }
@@ -385,8 +385,10 @@
      */
     @Override
     public int compare(String source, String target) {
-        if (source == null || target == null) {
-            throw new NullPointerException();
+        if (source == null) {
+            throw new NullPointerException("source == null");
+        } else if (target == null) {
+            throw new NullPointerException("target == null");
         }
         return icuColl.compare(source, target);
     }
diff --git a/luni/src/main/java/java/text/SimpleDateFormat.java b/luni/src/main/java/java/text/SimpleDateFormat.java
index 1f9b694..f682c0b 100644
--- a/luni/src/main/java/java/text/SimpleDateFormat.java
+++ b/luni/src/main/java/java/text/SimpleDateFormat.java
@@ -411,9 +411,6 @@
     /**
      * Returns a new {@code SimpleDateFormat} with the same pattern and
      * properties as this simple date format.
-     *
-     * @return a shallow copy of this simple date format.
-     * @see java.lang.Cloneable
      */
     @Override
     public Object clone() {
@@ -471,7 +468,7 @@
     @Override
     public AttributedCharacterIterator formatToCharacterIterator(Object object) {
         if (object == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("object == null");
         }
         if (object instanceof Date) {
             return formatToCharacterIteratorImpl((Date) object);
@@ -1070,24 +1067,42 @@
     }
 
     private Number parseNumber(int max, String string, ParsePosition position) {
-        int digit, length = string.length(), result = 0;
+        int length = string.length();
         int index = position.getIndex();
         if (max > 0 && max < length - index) {
             length = index + max;
         }
-        while (index < length
-                && (string.charAt(index) == ' ' || string.charAt(index) == '\t')) {
-            index++;
+        while (index < length && (string.charAt(index) == ' ' || string.charAt(index) == '\t')) {
+            ++index;
         }
         if (max == 0) {
             position.setIndex(index);
-            return numberFormat.parse(string, position);
+            Number n = numberFormat.parse(string, position);
+            // In RTL locales, NumberFormat might have parsed "2012-" in an ISO date as the
+            // negative number -2012.
+            // Ideally, we wouldn't have this broken API that exposes a NumberFormat and expects
+            // us to use it. The next best thing would be a way to ask the NumberFormat to parse
+            // positive numbers only, but icu4c supports negative (BCE) years. The best we can do
+            // is try to recognize when icu4c has done this, and undo it.
+            if (n != null && n.longValue() < 0) {
+                if (numberFormat instanceof DecimalFormat) {
+                    DecimalFormat df = (DecimalFormat) numberFormat;
+                    char lastChar = string.charAt(position.getIndex() - 1);
+                    char minusSign = df.getDecimalFormatSymbols().getMinusSign();
+                    if (lastChar == minusSign) {
+                        n = Long.valueOf(-n.longValue()); // Make the value positive.
+                        position.setIndex(position.getIndex() - 1); // Spit out the negative sign.
+                    }
+                }
+            }
+            return n;
         }
 
-        while (index < length
-                && (digit = Character.digit(string.charAt(index), 10)) != -1) {
-            index++;
+        int result = 0;
+        int digit;
+        while (index < length && (digit = Character.digit(string.charAt(index), 10)) != -1) {
             result = result * 10 + digit;
+            ++index;
         }
         if (index == position.getIndex()) {
             position.setErrorIndex(index);
@@ -1174,14 +1189,18 @@
                     }
                     int raw = zone.getRawOffset();
                     if (j == TimeZones.LONG_NAME_DST || j == TimeZones.SHORT_NAME_DST) {
-                        /*
-                         * TODO, http://b/4723412
-                         * We can't use TimeZone#getDSTSavings here because that
-                         * will return 0 if the zone no longer uses DST. We
-                         * should change this to use TimeZone.getOffset(long),
-                         * which requires the complete date to be parsed first.
-                         */
-                        raw += 3600000;
+                        // Not all time zones use a one-hour difference, so we need to query
+                        // the TimeZone. (Australia/Lord_Howe is the usual example of this.)
+                        int dstSavings = zone.getDSTSavings();
+                        // One problem with TimeZone.getDSTSavings is that it will return 0 if the
+                        // time zone has stopped using DST, even if we're parsing a date from
+                        // the past. In that case, assume the default.
+                        if (dstSavings == 0) {
+                            // TODO: we should change this to use TimeZone.getOffset(long),
+                            // but that requires the complete date to be parsed first.
+                            dstSavings = 3600000;
+                        }
+                        raw += dstSavings;
                     }
                     calendar.setTimeZone(new SimpleTimeZone(raw, ""));
                     return offset + element[j].length();
diff --git a/luni/src/main/java/java/util/AbstractQueue.java b/luni/src/main/java/java/util/AbstractQueue.java
index d368ac9..47f81fd 100644
--- a/luni/src/main/java/java/util/AbstractQueue.java
+++ b/luni/src/main/java/java/util/AbstractQueue.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util;
@@ -150,9 +150,9 @@
      */
     public boolean addAll(Collection<? extends E> c) {
         if (c == null)
-            throw new NullPointerException();
+            throw new NullPointerException("c == null");
         if (c == this)
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("c == this");
         boolean modified = false;
         for (E e : c)
             if (add(e))
diff --git a/luni/src/main/java/java/util/ArrayDeque.java b/luni/src/main/java/java/util/ArrayDeque.java
index fafcdb4..5ee3f81 100644
--- a/luni/src/main/java/java/util/ArrayDeque.java
+++ b/luni/src/main/java/java/util/ArrayDeque.java
@@ -1,6 +1,6 @@
 /*
  * Written by Josh Bloch of Google Inc. and released to the public domain,
- * as explained at http://creativecommons.org/licenses/publicdomain.
+ * as explained at http://creativecommons.org/publicdomain/zero/1.0/.
  */
 
 package java.util;
@@ -9,8 +9,6 @@
 // removed link to collections framework docs
 // END android-note
 
-import java.io.*;
-
 /**
  * Resizable-array implementation of the {@link Deque} interface.  Array
  * deques have no capacity restrictions; they grow as necessary to support
@@ -53,7 +51,7 @@
  * @param <E> the type of elements held in this collection
  */
 public class ArrayDeque<E> extends AbstractCollection<E>
-                           implements Deque<E>, Cloneable, Serializable
+                           implements Deque<E>, Cloneable, java.io.Serializable
 {
     /**
      * The array in which the elements of the deque are stored.
@@ -65,7 +63,7 @@
      * other.  We also guarantee that all array cells not holding
      * deque elements are always null.
      */
-    private transient E[] elements;
+    private transient Object[] elements;
 
     /**
      * The index of the element at the head of the deque (which is the
@@ -109,7 +107,7 @@
             if (initialCapacity < 0)   // Too many elements, must back off
                 initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
         }
-        elements = (E[]) new Object[initialCapacity];
+        elements = new Object[initialCapacity];
     }
 
     /**
@@ -127,7 +125,7 @@
         Object[] a = new Object[newCapacity];
         System.arraycopy(elements, p, a, 0, r);
         System.arraycopy(elements, 0, a, r, p);
-        elements = (E[])a;
+        elements = a;
         head = 0;
         tail = n;
     }
@@ -155,7 +153,7 @@
      * sufficient to hold 16 elements.
      */
     public ArrayDeque() {
-        elements = (E[]) new Object[16];
+        elements = new Object[16];
     }
 
     /**
@@ -195,7 +193,7 @@
      */
     public void addFirst(E e) {
         if (e == null)
-            throw new NullPointerException();
+            throw new NullPointerException("e == null");
         elements[head = (head - 1) & (elements.length - 1)] = e;
         if (head == tail)
             doubleCapacity();
@@ -211,7 +209,7 @@
      */
     public void addLast(E e) {
         if (e == null)
-            throw new NullPointerException();
+            throw new NullPointerException("e == null");
         elements[tail] = e;
         if ( (tail = (tail + 1) & (elements.length - 1)) == head)
             doubleCapacity();
@@ -263,7 +261,8 @@
 
     public E pollFirst() {
         int h = head;
-        E result = elements[h]; // Element is null if deque empty
+        @SuppressWarnings("unchecked") E result = (E) elements[h];
+        // Element is null if deque empty
         if (result == null)
             return null;
         elements[h] = null;     // Must null out slot
@@ -273,7 +272,7 @@
 
     public E pollLast() {
         int t = (tail - 1) & (elements.length - 1);
-        E result = elements[t];
+        @SuppressWarnings("unchecked") E result = (E) elements[t];
         if (result == null)
             return null;
         elements[t] = null;
@@ -285,28 +284,33 @@
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E getFirst() {
-        E x = elements[head];
-        if (x == null)
+        @SuppressWarnings("unchecked") E result = (E) elements[head];
+        if (result == null)
             throw new NoSuchElementException();
-        return x;
+        return result;
     }
 
     /**
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E getLast() {
-        E x = elements[(tail - 1) & (elements.length - 1)];
-        if (x == null)
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[(tail - 1) & (elements.length - 1)];
+        if (result == null)
             throw new NoSuchElementException();
-        return x;
+        return result;
     }
 
     public E peekFirst() {
-        return elements[head]; // elements[head] is null if deque empty
+        @SuppressWarnings("unchecked") E result = (E) elements[head];
+        // elements[head] is null if deque empty
+        return result;
     }
 
     public E peekLast() {
-        return elements[(tail - 1) & (elements.length - 1)];
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[(tail - 1) & (elements.length - 1)];
+        return result;
     }
 
     /**
@@ -326,7 +330,7 @@
             return false;
         int mask = elements.length - 1;
         int i = head;
-        E x;
+        Object x;
         while ( (x = elements[i]) != null) {
             if (o.equals(x)) {
                 delete(i);
@@ -354,7 +358,7 @@
             return false;
         int mask = elements.length - 1;
         int i = (tail - 1) & mask;
-        E x;
+        Object x;
         while ( (x = elements[i]) != null) {
             if (o.equals(x)) {
                 delete(i);
@@ -499,7 +503,7 @@
      */
     private boolean delete(int i) {
         checkInvariants();
-        final E[] elements = this.elements;
+        final Object[] elements = this.elements;
         final int mask = elements.length - 1;
         final int h = head;
         final int t = tail;
@@ -597,7 +601,7 @@
         public E next() {
             if (cursor == fence)
                 throw new NoSuchElementException();
-            E result = elements[cursor];
+            @SuppressWarnings("unchecked") E result = (E) elements[cursor];
             // This check doesn't catch all possible comodifications,
             // but does catch the ones that corrupt traversal
             if (tail != fence || result == null)
@@ -636,7 +640,7 @@
             if (cursor == fence)
                 throw new NoSuchElementException();
             cursor = (cursor - 1) & (elements.length - 1);
-            E result = elements[cursor];
+            @SuppressWarnings("unchecked") E result = (E) elements[cursor];
             if (head != fence || result == null)
                 throw new ConcurrentModificationException();
             lastRet = cursor;
@@ -667,7 +671,7 @@
             return false;
         int mask = elements.length - 1;
         int i = head;
-        E x;
+        Object x;
         while ( (x = elements[i]) != null) {
             if (o.equals(x))
                 return true;
@@ -750,8 +754,7 @@
      * The following code can be used to dump the deque into a newly
      * allocated array of <tt>String</tt>:
      *
-     * <pre>
-     *     String[] y = x.toArray(new String[0]);</pre>
+     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
      *
      * Note that <tt>toArray(new Object[0])</tt> is identical in function to
      * <tt>toArray()</tt>.
@@ -765,6 +768,7 @@
      *         this deque
      * @throws NullPointerException if the specified array is null
      */
+    @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
         int size = size();
         if (a.length < size)
@@ -785,6 +789,7 @@
      */
     public ArrayDeque<E> clone() {
         try {
+            @SuppressWarnings("unchecked")
             ArrayDeque<E> result = (ArrayDeque<E>) super.clone();
             result.elements = Arrays.copyOf(elements, elements.length);
             return result;
@@ -806,7 +811,8 @@
      * followed by all of its elements (each an object reference) in
      * first-to-last order.
      */
-    private void writeObject(ObjectOutputStream s) throws IOException {
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws java.io.IOException {
         s.defaultWriteObject();
 
         // Write out size
@@ -821,8 +827,8 @@
     /**
      * Deserialize this deque.
      */
-    private void readObject(ObjectInputStream s)
-            throws IOException, ClassNotFoundException {
+    private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
         s.defaultReadObject();
 
         // Read in size and allocate array
@@ -833,6 +839,6 @@
 
         // Read in all elements in the proper order.
         for (int i = 0; i < size; i++)
-            elements[i] = (E)s.readObject();
+            elements[i] = s.readObject();
     }
 }
diff --git a/luni/src/main/java/java/util/Arrays.java b/luni/src/main/java/java/util/Arrays.java
index 9d0f4a4..4a149b7 100644
--- a/luni/src/main/java/java/util/Arrays.java
+++ b/luni/src/main/java/java/util/Arrays.java
@@ -35,7 +35,7 @@
 
         ArrayList(E[] storage) {
             if (storage == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("storage == null");
             }
             a = storage;
         }
@@ -2459,7 +2459,7 @@
      */
     public static boolean[] copyOf(boolean[] original, int newLength) {
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength);
     }
@@ -2478,7 +2478,7 @@
      */
     public static byte[] copyOf(byte[] original, int newLength) {
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength);
     }
@@ -2497,7 +2497,7 @@
      */
     public static char[] copyOf(char[] original, int newLength) {
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength);
     }
@@ -2516,7 +2516,7 @@
      */
     public static double[] copyOf(double[] original, int newLength) {
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength);
     }
@@ -2535,7 +2535,7 @@
      */
     public static float[] copyOf(float[] original, int newLength) {
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength);
     }
@@ -2554,7 +2554,7 @@
      */
     public static int[] copyOf(int[] original, int newLength) {
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength);
     }
@@ -2573,7 +2573,7 @@
      */
     public static long[] copyOf(long[] original, int newLength) {
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength);
     }
@@ -2592,7 +2592,7 @@
      */
     public static short[] copyOf(short[] original, int newLength) {
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength);
     }
@@ -2611,10 +2611,10 @@
      */
     public static <T> T[] copyOf(T[] original, int newLength) {
         if (original == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("original == null");
         }
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength);
     }
@@ -2636,7 +2636,7 @@
     public static <T, U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
         // We use the null pointer check in copyOfRange for exception priority compatibility.
         if (newLength < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(newLength));
         }
         return copyOfRange(original, 0, newLength, newType);
     }
diff --git a/luni/src/main/java/java/util/BitSet.java b/luni/src/main/java/java/util/BitSet.java
index a4ee4c1..9dfe35e 100644
--- a/luni/src/main/java/java/util/BitSet.java
+++ b/luni/src/main/java/java/util/BitSet.java
@@ -85,7 +85,7 @@
      */
     public BitSet(int bitCount) {
         if (bitCount < 0) {
-            throw new NegativeArraySizeException();
+            throw new NegativeArraySizeException(Integer.toString(bitCount));
         }
         this.bits = arrayForBits(bitCount);
         this.longCount = 0;
diff --git a/luni/src/main/java/java/util/Calendar.java b/luni/src/main/java/java/util/Calendar.java
index bef6e26..81d01fb 100644
--- a/luni/src/main/java/java/util/Calendar.java
+++ b/luni/src/main/java/java/util/Calendar.java
@@ -877,8 +877,7 @@
         return getTimeInMillis() == cal.getTimeInMillis()
                 && isLenient() == cal.isLenient()
                 && getFirstDayOfWeek() == cal.getFirstDayOfWeek()
-                && getMinimalDaysInFirstWeek() == cal
-                        .getMinimalDaysInFirstWeek()
+                && getMinimalDaysInFirstWeek() == cal.getMinimalDaysInFirstWeek()
                 && getTimeZone().equals(cal.getTimeZone());
     }
 
@@ -903,11 +902,8 @@
     }
 
     /**
-     * Gets the maximum value of the specified field for the current date.
-     *
-     * @param field
-     *            the field.
-     * @return the maximum value of the specified field.
+     * Returns the maximum value of the specified field for the current date.
+     * For example, the maximum number of days in the current month.
      */
     public int getActualMaximum(int field) {
         int value, next;
@@ -1393,7 +1389,7 @@
      */
     public int compareTo(Calendar anotherCalendar) {
         if (anotherCalendar == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("anotherCalendar == null");
         }
         long timeInMillis = getTimeInMillis();
         long anotherTimeInMillis = anotherCalendar.getTimeInMillis();
diff --git a/luni/src/main/java/java/util/Collections.java b/luni/src/main/java/java/util/Collections.java
index b6729b4..d49ca85 100644
--- a/luni/src/main/java/java/util/Collections.java
+++ b/luni/src/main/java/java/util/Collections.java
@@ -1412,7 +1412,7 @@
     @SuppressWarnings("unchecked")
     public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T object) {
         if (list == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("list == null");
         }
         if (list.isEmpty()) {
             return -1;
@@ -1916,7 +1916,7 @@
     @SuppressWarnings("unchecked")
     public static void swap(List<?> list, int index1, int index2) {
         if (list == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("list == null");
         }
         final int size = list.size();
         if (index1 < 0 || index1 >= size || index2 < 0 || index2 >= size) {
@@ -2174,7 +2174,7 @@
     public static <T> Collection<T> synchronizedCollection(
             Collection<T> collection) {
         if (collection == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("collection == null");
         }
         return new SynchronizedCollection<T>(collection);
     }
@@ -2189,7 +2189,7 @@
      */
     public static <T> List<T> synchronizedList(List<T> list) {
         if (list == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("list == null");
         }
         if (list instanceof RandomAccess) {
             return new SynchronizedRandomAccessList<T>(list);
@@ -2207,7 +2207,7 @@
      */
     public static <K, V> Map<K, V> synchronizedMap(Map<K, V> map) {
         if (map == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("map == null");
         }
         return new SynchronizedMap<K, V>(map);
     }
@@ -2222,7 +2222,7 @@
      */
     public static <E> Set<E> synchronizedSet(Set<E> set) {
         if (set == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("set == null");
         }
         return new SynchronizedSet<E>(set);
     }
@@ -2238,7 +2238,7 @@
     public static <K, V> SortedMap<K, V> synchronizedSortedMap(
             SortedMap<K, V> map) {
         if (map == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("map == null");
         }
         return new SynchronizedSortedMap<K, V>(map);
     }
@@ -2253,7 +2253,7 @@
      */
     public static <E> SortedSet<E> synchronizedSortedSet(SortedSet<E> set) {
         if (set == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("set == null");
         }
         return new SynchronizedSortedSet<E>(set);
     }
@@ -2271,7 +2271,7 @@
     public static <E> Collection<E> unmodifiableCollection(
             Collection<? extends E> collection) {
         if (collection == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("collection == null");
         }
         return new UnmodifiableCollection<E>((Collection<E>) collection);
     }
@@ -2288,7 +2288,7 @@
     @SuppressWarnings("unchecked")
     public static <E> List<E> unmodifiableList(List<? extends E> list) {
         if (list == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("list == null");
         }
         if (list instanceof RandomAccess) {
             return new UnmodifiableRandomAccessList<E>((List<E>) list);
@@ -2309,7 +2309,7 @@
     public static <K, V> Map<K, V> unmodifiableMap(
             Map<? extends K, ? extends V> map) {
         if (map == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("map == null");
         }
         return new UnmodifiableMap<K, V>((Map<K, V>) map);
     }
@@ -2326,7 +2326,7 @@
     @SuppressWarnings("unchecked")
     public static <E> Set<E> unmodifiableSet(Set<? extends E> set) {
         if (set == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("set == null");
         }
         return new UnmodifiableSet<E>((Set<E>) set);
     }
@@ -2344,7 +2344,7 @@
     public static <K, V> SortedMap<K, V> unmodifiableSortedMap(
             SortedMap<K, ? extends V> map) {
         if (map == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("map == null");
         }
         return new UnmodifiableSortedMap<K, V>((SortedMap<K, V>) map);
     }
@@ -2360,7 +2360,7 @@
      */
     public static <E> SortedSet<E> unmodifiableSortedSet(SortedSet<E> set) {
         if (set == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("set == null");
         }
         return new UnmodifiableSortedSet<E>(set);
     }
@@ -2381,7 +2381,7 @@
      */
     public static int frequency(Collection<?> c, Object o) {
         if (c == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("c == null");
         }
         if (c.isEmpty()) {
             return 0;
@@ -2834,8 +2834,10 @@
         Class<E> type;
 
         public CheckedCollection(Collection<E> c, Class<E> type) {
-            if (c == null || type == null) {
-                throw new NullPointerException();
+            if (c == null) {
+                throw new NullPointerException("c == null");
+            } else if (type == null) {
+                throw new NullPointerException("type == null");
             }
             this.c = c;
             this.type = type;
@@ -3079,8 +3081,12 @@
         Class<V> valueType;
 
         private CheckedMap(Map<K, V> m, Class<K> keyType, Class<V> valueType) {
-            if (m == null || keyType == null || valueType == null) {
-                throw new NullPointerException();
+            if (m == null) {
+                throw new NullPointerException("m == null");
+            } else if (keyType == null) {
+                throw new NullPointerException("keyType == null");
+            } else if (valueType == null) {
+                throw new NullPointerException("valueType == null");
             }
             this.m = m;
             this.keyType = keyType;
@@ -3172,7 +3178,7 @@
 
             public CheckedEntry(Map.Entry<K, V> e, Class<V> valueType) {
                 if (e == null) {
-                    throw new NullPointerException();
+                    throw new NullPointerException("e == null");
                 }
                 this.e = e;
                 this.valueType = valueType;
diff --git a/luni/src/main/java/java/util/Deque.java b/luni/src/main/java/java/util/Deque.java
index cb6bd90..f74a6b4 100644
--- a/luni/src/main/java/java/util/Deque.java
+++ b/luni/src/main/java/java/util/Deque.java
@@ -1,14 +1,13 @@
 /*
  * Written by Doug Lea and Josh Bloch with assistance from members of
  * JCP JSR-166 Expert Group and released to the public domain, as explained
- * at http://creativecommons.org/licenses/publicdomain
+ * at http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util;
 
 // BEGIN android-note
 // removed link to collections framework docs
-// changed {@link #offer(Object)} to {@link #offer} to satisfy DroidDoc
 // END android-note
 
 /**
@@ -356,7 +355,7 @@
      * <tt>true</tt> upon success and throwing an
      * <tt>IllegalStateException</tt> if no space is currently available.
      * When using a capacity-restricted deque, it is generally preferable to
-     * use {@link #offer offer}.
+     * use {@link #offer(Object) offer}.
      *
      * <p>This method is equivalent to {@link #addLast}.
      *
diff --git a/luni/src/main/java/java/util/DualPivotQuicksort.java b/luni/src/main/java/java/util/DualPivotQuicksort.java
index 97797d1..5d2f77f 100644
--- a/luni/src/main/java/java/util/DualPivotQuicksort.java
+++ b/luni/src/main/java/java/util/DualPivotQuicksort.java
@@ -1565,7 +1565,7 @@
 
         for (int k = left; k <= n; k++) {
             float ak = a[k];
-            if (ak == 0.0f && NEGATIVE_ZERO == Float.floatToIntBits(ak)) {
+            if (ak == 0.0f && NEGATIVE_ZERO == Float.floatToRawIntBits(ak)) {
                 a[k] = 0.0f;
                 numNegativeZeros++;
             } else if (ak != ak) { // i.e., ak is NaN
@@ -1938,7 +1938,7 @@
 
         for (int k = left; k <= n; k++) {
             double ak = a[k];
-            if (ak == 0.0d && NEGATIVE_ZERO == Double.doubleToLongBits(ak)) {
+            if (ak == 0.0d && NEGATIVE_ZERO == Double.doubleToRawLongBits(ak)) {
                 a[k] = 0.0d;
                 numNegativeZeros++;
             } else if (ak != ak) { // i.e., ak is NaN
diff --git a/luni/src/main/java/java/util/DuplicateFormatFlagsException.java b/luni/src/main/java/java/util/DuplicateFormatFlagsException.java
index d04db8e..2a2bc2e 100644
--- a/luni/src/main/java/java/util/DuplicateFormatFlagsException.java
+++ b/luni/src/main/java/java/util/DuplicateFormatFlagsException.java
@@ -37,7 +37,7 @@
      */
     public DuplicateFormatFlagsException(String f) {
         if (f == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("f == null");
         }
         flags = f;
     }
diff --git a/luni/src/main/java/java/util/EnumMap.java b/luni/src/main/java/java/util/EnumMap.java
index d3d42b4..a721ee3 100644
--- a/luni/src/main/java/java/util/EnumMap.java
+++ b/luni/src/main/java/java/util/EnumMap.java
@@ -773,7 +773,7 @@
     @SuppressWarnings("unchecked")
     private V putImpl(K key, V value) {
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
         keyType.cast(key); // Called to throw ClassCastException.
         int keyOrdinal = key.ordinal();
diff --git a/luni/src/main/java/java/util/FormatFlagsConversionMismatchException.java b/luni/src/main/java/java/util/FormatFlagsConversionMismatchException.java
index 5792877..5c36788 100644
--- a/luni/src/main/java/java/util/FormatFlagsConversionMismatchException.java
+++ b/luni/src/main/java/java/util/FormatFlagsConversionMismatchException.java
@@ -44,7 +44,7 @@
      */
     public FormatFlagsConversionMismatchException(String f, char c) {
         if (f == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("f == null");
         }
         this.f = f;
         this.c = c;
diff --git a/luni/src/main/java/java/util/Formatter.java b/luni/src/main/java/java/util/Formatter.java
index e9a2f4a..021da08 100644
--- a/luni/src/main/java/java/util/Formatter.java
+++ b/luni/src/main/java/java/util/Formatter.java
@@ -884,7 +884,7 @@
      */
     public Formatter(PrintStream ps) {
         if (ps == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("ps == null");
         }
         out = ps;
         locale = Locale.getDefault();
diff --git a/luni/src/main/java/java/util/GregorianCalendar.java b/luni/src/main/java/java/util/GregorianCalendar.java
index c0fd521..9ff9ccc 100644
--- a/luni/src/main/java/java/util/GregorianCalendar.java
+++ b/luni/src/main/java/java/util/GregorianCalendar.java
@@ -219,14 +219,6 @@
     private static int[] leastMaximums = new int[] { 1, 292269054, 11, 50, 3,
             28, 355, 7, 3, 1, 11, 23, 59, 59, 999, 50400000, 1200000 };
 
-    private boolean isCached;
-
-    private int[] cachedFields = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-    private long nextMidnightMillis = 0L;
-
-    private long lastMidnightMillis = 0L;
-
     private int currentYearSkew = 10;
 
     private int lastYearSkew = 0;
@@ -365,8 +357,6 @@
             throw new IllegalArgumentException();
         }
 
-        isCached = false;
-
         if (field == ERA) {
             complete();
             if (fields[ERA] == AD) {
@@ -468,19 +458,8 @@
         complete();
     }
 
-    /**
-     * Creates new instance of {@code GregorianCalendar} with the same properties.
-     *
-     * @return a shallow copy of this {@code GregorianCalendar}.
-     */
-    @Override
-    public Object clone() {
-        GregorianCalendar thisClone = (GregorianCalendar) super.clone();
-        thisClone.cachedFields = cachedFields.clone();
-        return thisClone;
-    }
-
-    private final void fullFieldsCalc(long timeVal, int millis, int zoneOffset) {
+    private void fullFieldsCalc(long timeVal, int zoneOffset) {
+        int millis = (int) (time % 86400000);
         long days = timeVal / 86400000;
 
         if (millis < 0) {
@@ -583,31 +562,6 @@
         }
     }
 
-    private final void cachedFieldsCheckAndGet(long timeVal,
-            long newTimeMillis, long newTimeMillisAdjusted, int millis,
-            int zoneOffset) {
-        int dstOffset = fields[DST_OFFSET];
-        if (!isCached
-                || newTimeMillis >= nextMidnightMillis
-                || newTimeMillis <= lastMidnightMillis
-                || cachedFields[4] != zoneOffset
-                || (dstOffset == 0 && (newTimeMillisAdjusted >= nextMidnightMillis))
-                || (dstOffset != 0 && (newTimeMillisAdjusted <= lastMidnightMillis))) {
-            fullFieldsCalc(timeVal, millis, zoneOffset);
-            isCached = false;
-        } else {
-            fields[YEAR] = cachedFields[0];
-            fields[MONTH] = cachedFields[1];
-            fields[DATE] = cachedFields[2];
-            fields[DAY_OF_WEEK] = cachedFields[3];
-            fields[ERA] = cachedFields[5];
-            fields[WEEK_OF_YEAR] = cachedFields[6];
-            fields[WEEK_OF_MONTH] = cachedFields[7];
-            fields[DAY_OF_YEAR] = cachedFields[8];
-            fields[DAY_OF_WEEK_IN_MONTH] = cachedFields[9];
-        }
-    }
-
     @Override
     protected void computeFields() {
         TimeZone timeZone = getTimeZone();
@@ -616,99 +570,11 @@
         fields[DST_OFFSET] = dstOffset;
         fields[ZONE_OFFSET] = zoneOffset;
 
-        int millis = (int) (time % 86400000);
-        int savedMillis = millis;
-        // compute without a change in daylight saving time
-        int offset = zoneOffset + dstOffset;
-        long newTime = time + offset;
-
-        if (time > 0L && newTime < 0L && offset > 0) {
-            newTime = 0x7fffffffffffffffL;
-        } else if (time < 0L && newTime > 0L && offset < 0) {
-            newTime = 0x8000000000000000L;
-        }
-
-        // FIXME: I don't think this caching ever really gets used, because it requires that the
-        // time zone doesn't use daylight savings (ever). So unless you're somewhere like Taiwan...
-        if (isCached) {
-            if (millis < 0) {
-                millis += 86400000;
-            }
-
-            // Cannot add ZONE_OFFSET to time as it might overflow
-            millis += zoneOffset;
-            millis += dstOffset;
-
-            if (millis < 0) {
-                millis += 86400000;
-            } else if (millis >= 86400000) {
-                millis -= 86400000;
-            }
-
-            fields[MILLISECOND] = (millis % 1000);
-            millis /= 1000;
-            fields[SECOND] = (millis % 60);
-            millis /= 60;
-            fields[MINUTE] = (millis % 60);
-            millis /= 60;
-            fields[HOUR_OF_DAY] = (millis % 24);
-            millis /= 24;
-            fields[AM_PM] = fields[HOUR_OF_DAY] > 11 ? 1 : 0;
-            fields[HOUR] = fields[HOUR_OF_DAY] % 12;
-
-            // FIXME: this has to be wrong; useDaylightTime doesn't mean what they think it means!
-            long newTimeAdjusted = newTime;
-            if (timeZone.useDaylightTime()) {
-                int dstSavings = timeZone.getDSTSavings();
-                newTimeAdjusted += (dstOffset == 0) ? dstSavings : -dstSavings;
-            }
-
-            if (newTime > 0L && newTimeAdjusted < 0L && dstOffset == 0) {
-                newTimeAdjusted = 0x7fffffffffffffffL;
-            } else if (newTime < 0L && newTimeAdjusted > 0L && dstOffset != 0) {
-                newTimeAdjusted = 0x8000000000000000L;
-            }
-
-            cachedFieldsCheckAndGet(time, newTime, newTimeAdjusted,
-                    savedMillis, zoneOffset);
-        } else {
-            fullFieldsCalc(time, savedMillis, zoneOffset);
-        }
+        fullFieldsCalc(time, zoneOffset);
 
         for (int i = 0; i < FIELD_COUNT; i++) {
             isSet[i] = true;
         }
-
-        // Caching
-        if (!isCached
-                && newTime != 0x7fffffffffffffffL
-                && newTime != 0x8000000000000000L
-                && (!timeZone.useDaylightTime() || timeZone instanceof SimpleTimeZone)) {
-            int cacheMillis = 0;
-
-            cachedFields[0] = fields[YEAR];
-            cachedFields[1] = fields[MONTH];
-            cachedFields[2] = fields[DATE];
-            cachedFields[3] = fields[DAY_OF_WEEK];
-            cachedFields[4] = zoneOffset;
-            cachedFields[5] = fields[ERA];
-            cachedFields[6] = fields[WEEK_OF_YEAR];
-            cachedFields[7] = fields[WEEK_OF_MONTH];
-            cachedFields[8] = fields[DAY_OF_YEAR];
-            cachedFields[9] = fields[DAY_OF_WEEK_IN_MONTH];
-
-            cacheMillis += (23 - fields[HOUR_OF_DAY]) * 60 * 60 * 1000;
-            cacheMillis += (59 - fields[MINUTE]) * 60 * 1000;
-            cacheMillis += (59 - fields[SECOND]) * 1000;
-            nextMidnightMillis = newTime + cacheMillis;
-
-            cacheMillis = fields[HOUR_OF_DAY] * 60 * 60 * 1000;
-            cacheMillis += fields[MINUTE] * 60 * 1000;
-            cacheMillis += fields[SECOND] * 1000;
-            lastMidnightMillis = newTime - cacheMillis;
-
-            isCached = true;
-        }
     }
 
     @Override
@@ -939,19 +805,17 @@
         return (int) days + 1;
     }
 
-    private long daysFromBaseYear(int iyear) {
-        long year = iyear;
-
+    private long daysFromBaseYear(long year) {
         if (year >= 1970) {
             long days = (year - 1970) * 365 + ((year - 1969) / 4);
             if (year > changeYear) {
                 days -= ((year - 1901) / 100) - ((year - 1601) / 400);
             } else {
-                if(year == changeYear){
+                if (year == changeYear) {
                     days += currentYearSkew;
-                }else if(year == changeYear -1){
+                } else if (year == changeYear - 1) {
                     days += lastYearSkew;
-                }else{
+                } else {
                     days += julianSkew;
                 }
             }
@@ -995,21 +859,10 @@
     }
 
     /**
-     * Compares the specified {@code Object} to this {@code GregorianCalendar} and returns whether
-     * they are equal. To be equal, the {@code Object} must be an instance of {@code GregorianCalendar} and
-     * have the same properties.
-     *
-     * @param object
-     *            the {@code Object} to compare with this {@code GregorianCalendar}.
-     * @return {@code true} if {@code object} is equal to this
-     *         {@code GregorianCalendar}, {@code false} otherwise.
-     * @throws IllegalArgumentException
-     *                if the time is not set and the time cannot be computed
-     *                from the current field values.
-     * @see #hashCode
+     * Returns true if {@code object} is a GregorianCalendar with the same
+     * properties.
      */
-    @Override
-    public boolean equals(Object object) {
+    @Override public boolean equals(Object object) {
         if (!(object instanceof GregorianCalendar)) {
             return false;
         }
@@ -1020,28 +873,12 @@
                 && gregorianCutover == ((GregorianCalendar) object).gregorianCutover;
     }
 
-    /**
-     * Gets the maximum value of the specified field for the current date. For
-     * example, the maximum number of days in the current month.
-     *
-     * @param field
-     *            the field.
-     * @return the maximum value of the specified field.
-     */
-    @Override
-    public int getActualMaximum(int field) {
+    @Override public int getActualMaximum(int field) {
         int value;
         if ((value = maximums[field]) == leastMaximums[field]) {
             return value;
         }
 
-        switch (field) {
-            case WEEK_OF_YEAR:
-            case WEEK_OF_MONTH:
-                isCached = false;
-                break;
-        }
-
         complete();
         long orgTime = time;
         int result = 0;
@@ -1216,32 +1053,16 @@
             month++;
         }
         int dayOfWeek = mod7(dayCount - 3) + 1;
-        int offset = timeZone.getOffset(AD, year, month, date, dayOfWeek,
-                millis);
-        return offset;
+        return timeZone.getOffset(AD, year, month, date, dayOfWeek, millis);
     }
 
-    /**
-     * Returns an integer hash code for the receiver. Objects which are equal
-     * return the same value for this method.
-     *
-     * @return the receiver's hash.
-     *
-     * @see #equals
-     */
-    @Override
-    public int hashCode() {
+    @Override public int hashCode() {
         return super.hashCode()
                 + ((int) (gregorianCutover >>> 32) ^ (int) gregorianCutover);
     }
 
     /**
-     * Returns whether the specified year is a leap year.
-     *
-     * @param year
-     *            the year.
-     * @return {@code true} if the specified year is a leap year, {@code false}
-     *         otherwise.
+     * Returns true if {@code year} is a leap year.
      */
     public boolean isLeapYear(int year) {
         if (year > changeYear) {
@@ -1294,8 +1115,6 @@
             throw new IllegalArgumentException();
         }
 
-        isCached = false;
-
         complete();
         int days, day, mod, maxWeeks, newWeek;
         int max = -1;
@@ -1410,13 +1229,10 @@
 
     /**
      * Sets the gregorian change date of this calendar.
-     *
-     * @param date
-     *            a {@code Date} which represents the gregorian change date.
      */
     public void setGregorianChange(Date date) {
         gregorianCutover = date.getTime();
-        GregorianCalendar cal = new GregorianCalendar(TimeZone.GMT);
+        GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
         cal.setTime(date);
         changeYear = cal.get(YEAR);
         if (cal.get(ERA) == BC) {
@@ -1424,7 +1240,6 @@
         }
         julianSkew = ((changeYear - 2000) / 400) + julianError()
                 - ((changeYear - 2000) / 100);
-        isCached = false;
         int dayOfYear = cal.get(DAY_OF_YEAR);
         if (dayOfYear < julianSkew) {
             currentYearSkew = dayOfYear-1;
@@ -1433,30 +1248,14 @@
             lastYearSkew = 0;
             currentYearSkew = julianSkew;
         }
-        isCached = false;
     }
 
     private void writeObject(ObjectOutputStream stream) throws IOException {
         stream.defaultWriteObject();
     }
 
-    private void readObject(ObjectInputStream stream) throws IOException,
-            ClassNotFoundException {
-
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
         stream.defaultReadObject();
         setGregorianChange(new Date(gregorianCutover));
-        isCached = false;
-    }
-
-    @Override
-    public void setFirstDayOfWeek(int value) {
-        super.setFirstDayOfWeek(value);
-        isCached = false;
-    }
-
-    @Override
-    public void setMinimalDaysInFirstWeek(int value) {
-        super.setMinimalDaysInFirstWeek(value);
-        isCached = false;
     }
 }
diff --git a/luni/src/main/java/java/util/Hashtable.java b/luni/src/main/java/java/util/Hashtable.java
index cea29da..a4e24bc 100644
--- a/luni/src/main/java/java/util/Hashtable.java
+++ b/luni/src/main/java/java/util/Hashtable.java
@@ -313,7 +313,7 @@
      */
     public synchronized boolean containsValue(Object value) {
         if (value == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("value == null");
         }
 
         HashtableEntry[] tab = table;
@@ -361,8 +361,10 @@
      * @see java.lang.Object#equals
      */
     public synchronized V put(K key, V value) {
-        if (value == null) {
-            throw new NullPointerException();
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        } else if (value == null) {
+            throw new NullPointerException("value == null");
         }
         int hash = secondaryHash(key.hashCode());
         HashtableEntry<K, V>[] tab = table;
@@ -395,8 +397,10 @@
      * ensure that capacity is sufficient, and does not increment modCount.
      */
     private void constructorPut(K key, V value) {
-        if (value == null) {
-            throw new NullPointerException();
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        } else if (value == null) {
+            throw new NullPointerException("value == null");
         }
         int hash = secondaryHash(key.hashCode());
         HashtableEntry<K, V>[] tab = table;
@@ -680,7 +684,7 @@
 
         public final V setValue(V value) {
             if (value == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("value == null");
             }
             V oldValue = this.value;
             this.value = value;
diff --git a/luni/src/main/java/java/util/IllegalFormatConversionException.java b/luni/src/main/java/java/util/IllegalFormatConversionException.java
index 31c0eed..af986f6 100644
--- a/luni/src/main/java/java/util/IllegalFormatConversionException.java
+++ b/luni/src/main/java/java/util/IllegalFormatConversionException.java
@@ -46,7 +46,7 @@
     public IllegalFormatConversionException(char c, Class<?> arg) {
         this.c = c;
         if (arg == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("arg == null");
         }
         this.arg = arg;
     }
diff --git a/luni/src/main/java/java/util/IllegalFormatFlagsException.java b/luni/src/main/java/java/util/IllegalFormatFlagsException.java
index 6947912..4946c55 100644
--- a/luni/src/main/java/java/util/IllegalFormatFlagsException.java
+++ b/luni/src/main/java/java/util/IllegalFormatFlagsException.java
@@ -38,7 +38,7 @@
      */
     public IllegalFormatFlagsException(String flags) {
         if (flags == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("flags == null");
         }
         this.flags = flags;
     }
diff --git a/luni/src/main/java/java/util/ListResourceBundle.java b/luni/src/main/java/java/util/ListResourceBundle.java
index 1508b93..fc6ab97 100644
--- a/luni/src/main/java/java/util/ListResourceBundle.java
+++ b/luni/src/main/java/java/util/ListResourceBundle.java
@@ -108,7 +108,7 @@
     public final Object handleGetObject(String key) {
         initializeTable();
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
         return table.get(key);
     }
diff --git a/luni/src/main/java/java/util/MissingFormatArgumentException.java b/luni/src/main/java/java/util/MissingFormatArgumentException.java
index ce72efa..1733501 100644
--- a/luni/src/main/java/java/util/MissingFormatArgumentException.java
+++ b/luni/src/main/java/java/util/MissingFormatArgumentException.java
@@ -37,7 +37,7 @@
      */
     public MissingFormatArgumentException(String s) {
         if (s == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("s == null");
         }
         this.s = s;
     }
diff --git a/luni/src/main/java/java/util/MissingFormatWidthException.java b/luni/src/main/java/java/util/MissingFormatWidthException.java
index b6d0ca6..0a3b5ae 100644
--- a/luni/src/main/java/java/util/MissingFormatWidthException.java
+++ b/luni/src/main/java/java/util/MissingFormatWidthException.java
@@ -36,7 +36,7 @@
      */
     public MissingFormatWidthException(String s) {
         if (s == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("s == null");
         }
         this.s = s;
     }
diff --git a/luni/src/main/java/java/util/NavigableMap.java b/luni/src/main/java/java/util/NavigableMap.java
index 29961c8..beeb651 100644
--- a/luni/src/main/java/java/util/NavigableMap.java
+++ b/luni/src/main/java/java/util/NavigableMap.java
@@ -1,14 +1,13 @@
 /*
  * Written by Doug Lea and Josh Bloch with assistance from members of JCP
  * JSR-166 Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util;
 
 // BEGIN android-note
 // removed link to collections framework docs
-// changed {@link #subMap(Object)} to {@link #subMap} to satisfy DroidDoc
 // END android-note
 
 /**
@@ -48,9 +47,9 @@
  * method {@code put}.
  *
  * <p>Methods
- * {@link #subMap subMap(K, K)},
- * {@link #headMap headMap(K)}, and
- * {@link #tailMap tailMap(K)}
+ * {@link #subMap(Object, Object) subMap(K, K)},
+ * {@link #headMap(Object) headMap(K)}, and
+ * {@link #tailMap(Object) tailMap(K)}
  * are specified to return {@code SortedMap} to allow existing
  * implementations of {@code SortedMap} to be compatibly retrofitted to
  * implement {@code NavigableMap}, but extensions and implementations
diff --git a/luni/src/main/java/java/util/NavigableSet.java b/luni/src/main/java/java/util/NavigableSet.java
index cff0800..f410313 100644
--- a/luni/src/main/java/java/util/NavigableSet.java
+++ b/luni/src/main/java/java/util/NavigableSet.java
@@ -1,14 +1,13 @@
 /*
  * Written by Doug Lea and Josh Bloch with assistance from members of JCP
  * JSR-166 Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util;
 
 // BEGIN android-note
 // removed link to collections framework docs
-// changed {@link #subSet(Object)} to {@link #subSet} to satisfy DroidDoc
 // END android-note
 
 /**
@@ -41,9 +40,9 @@
  * Comparable} elements intrinsically do not permit {@code null}.)
  *
  * <p>Methods
- * {@link #subSet subSet(E, E)},
- * {@link #headSet headSet(E)}, and
- * {@link #tailSet tailSet(E)}
+ * {@link #subSet(Object, Object) subSet(E, E)},
+ * {@link #headSet(Object) headSet(E)}, and
+ * {@link #tailSet(Object) tailSet(E)}
  * are specified to return {@code SortedSet} to allow existing
  * implementations of {@code SortedSet} to be compatibly retrofitted to
  * implement {@code NavigableSet}, but extensions and implementations
diff --git a/luni/src/main/java/java/util/Observable.java b/luni/src/main/java/java/util/Observable.java
index 2c2877e..c984c68 100644
--- a/luni/src/main/java/java/util/Observable.java
+++ b/luni/src/main/java/java/util/Observable.java
@@ -49,7 +49,7 @@
      */
     public void addObserver(Observer observer) {
         if (observer == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("observer == null");
         }
         synchronized (this) {
             if (!observers.contains(observer))
diff --git a/luni/src/main/java/java/util/PriorityQueue.java b/luni/src/main/java/java/util/PriorityQueue.java
index 10c5968..e09eb05 100644
--- a/luni/src/main/java/java/util/PriorityQueue.java
+++ b/luni/src/main/java/java/util/PriorityQueue.java
@@ -186,7 +186,7 @@
      */
     public boolean offer(E o) {
         if (o == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("o == null");
         }
         growToSize(size + 1);
         elements[size] = o;
@@ -387,7 +387,7 @@
 
     private void initSize(Collection<? extends E> c) {
         if (c == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("c == null");
         }
         if (c.isEmpty()) {
             elements = newElementArray(1);
diff --git a/luni/src/main/java/java/util/Properties.java b/luni/src/main/java/java/util/Properties.java
index 1731ad8..57c6a00 100644
--- a/luni/src/main/java/java/util/Properties.java
+++ b/luni/src/main/java/java/util/Properties.java
@@ -243,7 +243,7 @@
      */
     public synchronized void load(InputStream in) throws IOException {
         if (in == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("in == null");
         }
         load(new InputStreamReader(in, "ISO-8859-1"));
     }
@@ -276,7 +276,7 @@
     @SuppressWarnings("fallthrough")
     public synchronized void load(Reader in) throws IOException {
         if (in == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("in == null");
         }
         int mode = NONE, unicode = 0, count = 0;
         char nextChar, buf[] = new char[40];
@@ -578,7 +578,7 @@
     public synchronized void loadFromXML(InputStream in) throws IOException,
             InvalidPropertiesFormatException {
         if (in == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("in == null");
         }
 
         if (builder == null) {
@@ -690,8 +690,10 @@
     public synchronized void storeToXML(OutputStream os, String comment,
             String encoding) throws IOException {
 
-        if (os == null || encoding == null) {
-            throw new NullPointerException();
+        if (os == null) {
+            throw new NullPointerException("os == null");
+        } else if (encoding == null) {
+            throw new NullPointerException("encoding == null");
         }
 
         /*
diff --git a/luni/src/main/java/java/util/PropertyResourceBundle.java b/luni/src/main/java/java/util/PropertyResourceBundle.java
index 4029ee1..dbbd139 100644
--- a/luni/src/main/java/java/util/PropertyResourceBundle.java
+++ b/luni/src/main/java/java/util/PropertyResourceBundle.java
@@ -46,7 +46,7 @@
      */
     public PropertyResourceBundle(InputStream stream) throws IOException {
         if (stream == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("stream == null");
         }
         resources = new Properties();
         resources.load(stream);
diff --git a/luni/src/main/java/java/util/Queue.java b/luni/src/main/java/java/util/Queue.java
index 5aef944..8b465e6 100644
--- a/luni/src/main/java/java/util/Queue.java
+++ b/luni/src/main/java/java/util/Queue.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util;
diff --git a/luni/src/main/java/java/util/Random.java b/luni/src/main/java/java/util/Random.java
index 7ce74cc..b0a92ff 100644
--- a/luni/src/main/java/java/util/Random.java
+++ b/luni/src/main/java/java/util/Random.java
@@ -140,25 +140,23 @@
      * section 3.4.1, subsection C, algorithm P.
      */
     public synchronized double nextGaussian() {
-        if (haveNextNextGaussian) { // if X1 has been returned, return the
-                                    // second Gaussian
+        if (haveNextNextGaussian) {
             haveNextNextGaussian = false;
             return nextNextGaussian;
         }
 
         double v1, v2, s;
         do {
-            v1 = 2 * nextDouble() - 1; // Generates two independent random
-                                        // variables U1, U2
+            v1 = 2 * nextDouble() - 1;
             v2 = 2 * nextDouble() - 1;
             s = v1 * v1 + v2 * v2;
-        } while (s >= 1);
-        double norm = Math.sqrt(-2 * Math.log(s) / s);
-        nextNextGaussian = v2 * norm; // should that not be norm instead
-                                        // of multiplier ?
+        } while (s >= 1 || s == 0);
+
+        // The specification says this uses StrictMath.
+        double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s) / s);
+        nextNextGaussian = v2 * multiplier;
         haveNextNextGaussian = true;
-        return v1 * norm; // should that not be norm instead of multiplier
-                            // ?
+        return v1 * multiplier;
     }
 
     /**
diff --git a/luni/src/main/java/java/util/ResourceBundle.java b/luni/src/main/java/java/util/ResourceBundle.java
index ff38b5b..f5c8285 100644
--- a/luni/src/main/java/java/util/ResourceBundle.java
+++ b/luni/src/main/java/java/util/ResourceBundle.java
@@ -211,8 +211,10 @@
      */
     public static ResourceBundle getBundle(String bundleName, Locale locale,
             ClassLoader loader) throws MissingResourceException {
-        if (loader == null || bundleName == null) {
-            throw new NullPointerException();
+        if (loader == null) {
+            throw new NullPointerException("loader == null");
+        } else if (bundleName == null) {
+            throw new NullPointerException("bundleName == null");
         }
         Locale defaultLocale = Locale.getDefault();
         if (!cacheLocale.equals(defaultLocale)) {
@@ -610,14 +612,14 @@
 
     public static void clearCache(ClassLoader loader) {
         if (loader == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("loader == null");
         }
         cache.remove(loader);
     }
 
     public boolean containsKey(String key) {
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
         return keySet().contains(key);
     }
@@ -665,8 +667,10 @@
 
         @Override
         public Locale getFallbackLocale(String baseName, Locale locale) {
-            if (baseName == null || locale == null) {
-                throw new NullPointerException();
+            if (baseName == null) {
+                throw new NullPointerException("baseName == null");
+            } else if (locale == null) {
+                throw new NullPointerException("locale == null");
             }
             return null;
         }
@@ -804,8 +808,10 @@
          * {@code locale}.
          */
         public List<Locale> getCandidateLocales(String baseName, Locale locale) {
-            if (baseName == null || locale == null) {
-                throw new NullPointerException();
+            if (baseName == null) {
+                throw new NullPointerException("baseName == null");
+            } else if (locale == null) {
+                throw new NullPointerException("locale == null");
             }
             List<Locale> retList = new ArrayList<Locale>();
             String language = locale.getLanguage();
@@ -829,7 +835,7 @@
          */
         public List<String> getFormats(String baseName) {
             if (baseName == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("baseName == null");
             }
             return format;
         }
@@ -838,8 +844,10 @@
          * Returns the fallback locale for {@code baseName} in {@code locale}.
          */
         public Locale getFallbackLocale(String baseName, Locale locale) {
-            if (baseName == null || locale == null) {
-                throw new NullPointerException();
+            if (baseName == null) {
+                throw new NullPointerException("baseName == null");
+            } else if (locale == null) {
+                throw new NullPointerException("locale == null");
             }
             if (Locale.getDefault() != locale) {
                 return Locale.getDefault();
@@ -872,8 +880,10 @@
                 String format, ClassLoader loader, boolean reload)
                 throws IllegalAccessException, InstantiationException,
                 IOException {
-            if (format == null || loader == null) {
-                throw new NullPointerException();
+            if (format == null) {
+                throw new NullPointerException("format == null");
+            } else if (loader == null) {
+                throw new NullPointerException("loader == null");
             }
             final String bundleName = toBundleName(baseName, locale);
             final ClassLoader clsloader = loader;
@@ -938,8 +948,10 @@
          * default is TTL_NO_EXPIRATION_CONTROL.
          */
         public long getTimeToLive(String baseName, Locale locale) {
-            if (baseName == null || locale == null) {
-                throw new NullPointerException();
+            if (baseName == null) {
+                throw new NullPointerException("baseName == null");
+            } else if (locale == null) {
+                throw new NullPointerException("locale == null");
             }
             return TTL_NO_EXPIRATION_CONTROL;
         }
@@ -966,7 +978,7 @@
                 long loadTime) {
             if (bundle == null) {
                 // FIXME what's the use of bundle?
-                throw new NullPointerException();
+                throw new NullPointerException("bundle == null");
             }
             String bundleName = toBundleName(baseName, locale);
             String suffix = format;
@@ -1004,7 +1016,7 @@
             final String preString = UNDER_SCORE;
             final String underline = UNDER_SCORE;
             if (baseName == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("baseName == null");
             }
             StringBuilder ret = new StringBuilder();
             StringBuilder prefix = new StringBuilder();
@@ -1044,7 +1056,7 @@
          */
         public final String toResourceName(String bundleName, String suffix) {
             if (suffix == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("suffix == null");
             }
             StringBuilder ret = new StringBuilder(bundleName.replace('.', '/'));
             ret.append('.');
diff --git a/luni/src/main/java/java/util/Scanner.java b/luni/src/main/java/java/util/Scanner.java
index 8f889b3..5f7d0e3 100644
--- a/luni/src/main/java/java/util/Scanner.java
+++ b/luni/src/main/java/java/util/Scanner.java
@@ -241,7 +241,7 @@
      */
     public Scanner(Readable src) {
         if (src == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("src == null");
         }
         input = src;
         initialization();
@@ -1664,7 +1664,7 @@
      */
     public Scanner useLocale(Locale l) {
         if (l == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("l == null");
         }
         this.locale = l;
         return this;
@@ -1724,7 +1724,7 @@
      */
     private void checkNull(Pattern pattern) {
         if (pattern == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("pattern == null");
         }
     }
 
diff --git a/luni/src/main/java/java/util/ServiceLoader.java b/luni/src/main/java/java/util/ServiceLoader.java
index beacaab..016ab3f 100644
--- a/luni/src/main/java/java/util/ServiceLoader.java
+++ b/luni/src/main/java/java/util/ServiceLoader.java
@@ -78,7 +78,7 @@
         // It makes no sense for service to be null.
         // classLoader is null if you want the system class loader.
         if (service == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("service == null");
         }
         this.service = service;
         this.classLoader = classLoader;
diff --git a/luni/src/main/java/java/util/SimpleTimeZone.java b/luni/src/main/java/java/util/SimpleTimeZone.java
index 6c9b443..93dc88e 100644
--- a/luni/src/main/java/java/util/SimpleTimeZone.java
+++ b/luni/src/main/java/java/util/SimpleTimeZone.java
@@ -217,10 +217,17 @@
             throw new IllegalArgumentException("Invalid daylightSavings: " + daylightSavings);
         }
         dstSavings = daylightSavings;
-        // TODO: do we need to set useDaylight is dstSavings != 0?
 
-        setStartRule(startMonth, startDay, startDayOfWeek, startTime);
-        setEndRule(endMonth, endDay, endDayOfWeek, endTime);
+        this.startMonth = startMonth;
+        this.startDay = startDay;
+        this.startDayOfWeek = startDayOfWeek;
+        this.startTime = startTime;
+        setStartMode();
+        this.endMonth = endMonth;
+        this.endDay = endDay;
+        this.endDayOfWeek = endDayOfWeek;
+        this.endTime = endTime;
+        setEndMode();
     }
 
     /**
diff --git a/luni/src/main/java/java/util/StringTokenizer.java b/luni/src/main/java/java/util/StringTokenizer.java
index 1b07604..e6686e8 100644
--- a/luni/src/main/java/java/util/StringTokenizer.java
+++ b/luni/src/main/java/java/util/StringTokenizer.java
@@ -91,13 +91,13 @@
      */
     public StringTokenizer(String string, String delimiters,
             boolean returnDelimiters) {
-        if (string != null) {
-            this.string = string;
-            this.delimiters = delimiters;
-            this.returnDelimiters = returnDelimiters;
-            this.position = 0;
-        } else
-            throw new NullPointerException();
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+        this.string = string;
+        this.delimiters = delimiters;
+        this.returnDelimiters = returnDelimiters;
+        this.position = 0;
     }
 
     /**
@@ -143,7 +143,7 @@
      */
     public boolean hasMoreTokens() {
         if (delimiters == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("delimiters == null");
         }
         int length = string.length();
         if (position < length) {
@@ -180,7 +180,7 @@
      */
     public String nextToken() {
         if (delimiters == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("delimiters == null");
         }
         int i = position;
         int length = string.length();
diff --git a/luni/src/main/java/java/util/TimeZone.java b/luni/src/main/java/java/util/TimeZone.java
index 34763cc..85011bc 100644
--- a/luni/src/main/java/java/util/TimeZone.java
+++ b/luni/src/main/java/java/util/TimeZone.java
@@ -17,7 +17,10 @@
 
 package java.util;
 
+import java.io.IOException;
 import java.io.Serializable;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import libcore.icu.TimeZones;
 import libcore.util.ZoneInfoDB;
 
@@ -28,7 +31,7 @@
  * <p>Most applications will use {@link #getDefault} which returns a {@code TimeZone} based on
  * the time zone where the program is running.
  *
- * <p>You can also get a specific {@code TimeZone} {@link #getTimeZone by id}.
+ * <p>You can also get a specific {@code TimeZone} {@link #getTimeZone by Olson ID}.
  *
  * <p>It is highly unlikely you'll ever want to use anything but the factory methods yourself.
  * Let classes like {@link Calendar} and {@link java.text.SimpleDateFormat} do the date
@@ -64,6 +67,8 @@
 public abstract class TimeZone implements Serializable, Cloneable {
     private static final long serialVersionUID = 3581463369166924961L;
 
+    private static final Pattern CUSTOM_ZONE_ID_PATTERN = Pattern.compile("^GMT[-+](\\d{1,2})(:?(\\d\\d))?$");
+
     /**
      * The short display name style, such as {@code PDT}. Requests for this
      * style may yield GMT offsets like {@code GMT-08:00}.
@@ -76,7 +81,8 @@
      */
     public static final int LONG = 1;
 
-    static final TimeZone GMT = new SimpleTimeZone(0, "GMT"); // Greenwich Mean Time
+    private static final TimeZone GMT = new SimpleTimeZone(0, "GMT");
+    private static final TimeZone UTC = new SimpleTimeZone(0, "UTC");
 
     private static TimeZone defaultTimeZone;
 
@@ -214,16 +220,27 @@
     }
 
     /**
-     * Returns the daylight savings offset in milliseconds for this time zone.
-     * The base implementation returns {@code 3600000} (1 hour) for time zones
-     * that use daylight savings time and {@code 0} for timezones that do not.
-     * Subclasses should override this method for other daylight savings
-     * offsets.
+     * Returns the latest daylight savings in milliseconds for this time zone, relative
+     * to this time zone's regular UTC offset (as returned by {@link #getRawOffset}).
      *
-     * <p>Note that this method doesn't tell you whether or not to apply the
+     * <p>This class returns {@code 3600000} (1 hour) for time zones
+     * that use daylight savings time and {@code 0} for timezones that do not,
+     * leaving it to subclasses to override this method for other daylight savings
+     * offsets. (There are time zones, such as {@code Australia/Lord_Howe},
+     * that use other values.)
+     *
+     * <p>Note that this method doesn't tell you whether or not to <i>apply</i> the
      * offset: you need to call {@code inDaylightTime} for the specific time
      * you're interested in. If this method returns a non-zero offset, that only
      * tells you that this {@code TimeZone} sometimes observes daylight savings.
+     *
+     * <p>Note also that this method doesn't necessarily return the value you need
+     * to apply to the time you're working with. This value can and does change over
+     * time for a given time zone.
+     *
+     * <p>It's highly unlikely that you should ever call this method. You
+     * probably want {@link #getOffset} instead, which tells you the offset
+     * for a specific point in time, and takes daylight savings into account for you.
      */
     public int getDSTSavings() {
         return useDaylightTime() ? 3600000 : 0;
@@ -265,17 +282,19 @@
     public abstract int getRawOffset();
 
     /**
-     * Returns a {@code TimeZone} suitable for {@code id}, or {@code GMT} for unknown ids.
+     * Returns a {@code TimeZone} corresponding to the given {@code id}, or {@code GMT}
+     * for unknown ids.
      *
-     * <p>An id can be an Olson name of the form <i>Area</i>/<i>Location</i>, such
+     * <p>An ID can be an Olson name of the form <i>Area</i>/<i>Location</i>, such
      * as {@code America/Los_Angeles}. The {@link #getAvailableIDs} method returns
      * the supported names.
      *
-     * <p>This method can also create a custom {@code TimeZone} using the following
-     * syntax: {@code GMT[+|-]hh[[:]mm]}. For example, {@code TimeZone.getTimeZone("GMT+14:00")}
-     * would return an object with a raw offset of +14 hours from UTC, and which does <i>not</i>
-     * use daylight savings. These are rarely useful, because they don't correspond to time
-     * zones actually in use.
+     * <p>This method can also create a custom {@code TimeZone} given an ID with the following
+     * syntax: {@code GMT[+|-]hh[[:]mm]}. For example, {@code "GMT+05:00"}, {@code "GMT+0500"},
+     * {@code "GMT+5:00"}, {@code "GMT+500"}, {@code "GMT+05"}, and {@code "GMT+5"} all return
+     * an object with a raw offset of +5 hours from UTC, and which does <i>not</i> use daylight
+     * savings. These are rarely useful, because they don't correspond to time zones actually
+     * in use by humans.
      *
      * <p>Other than the special cases "UTC" and "GMT" (which are synonymous in this context,
      * both corresponding to UTC), Android does not support the deprecated three-letter time
@@ -285,80 +304,66 @@
         if (id == null) {
             throw new NullPointerException("id == null");
         }
-        TimeZone zone = ZoneInfoDB.getTimeZone(id);
-        if (zone != null) {
-            return zone;
+
+        // Special cases? These can clone an existing instance.
+        // TODO: should we just add a cache to ZoneInfoDB instead?
+        if (id.length() == 3) {
+            if (id.equals("GMT")) {
+                return (TimeZone) GMT.clone();
+            }
+            if (id.equals("UTC")) {
+                return (TimeZone) UTC.clone();
+            }
         }
+
+        // In the database?
+        TimeZone zone = null;
+        try {
+            zone = ZoneInfoDB.makeTimeZone(id);
+        } catch (IOException ignored) {
+        }
+
+        // Custom time zone?
         if (zone == null && id.length() > 3 && id.startsWith("GMT")) {
             zone = getCustomTimeZone(id);
         }
-        if (zone == null) {
-            zone = (TimeZone) GMT.clone();
-        }
-        return zone;
+
+        // We never return null; on failure we return the equivalent of "GMT".
+        return (zone != null) ? zone : (TimeZone) GMT.clone();
     }
 
     /**
-     * Returns a new SimpleTimeZone for an id of the form "GMT[+|-]hh[[:]mm]", or null.
+     * Returns a new SimpleTimeZone for an ID of the form "GMT[+|-]hh[[:]mm]", or null.
      */
     private static TimeZone getCustomTimeZone(String id) {
-        char sign = id.charAt(3);
-        if (sign != '+' && sign != '-') {
+        Matcher m = CUSTOM_ZONE_ID_PATTERN.matcher(id);
+        if (!m.matches()) {
             return null;
         }
-        int[] position = new int[1];
-        String formattedName = formatTimeZoneName(id, 4);
-        int hour = parseNumber(formattedName, 4, position);
-        if (hour < 0 || hour > 23) {
-            return null;
-        }
-        int index = position[0];
-        if (index == -1) {
-            return null;
-        }
-        int raw = hour * 3600000;
-        if (index < formattedName.length() && formattedName.charAt(index) == ':') {
-            int minute = parseNumber(formattedName, index + 1, position);
-            if (position[0] == -1 || minute < 0 || minute > 59) {
-                return null;
+
+        int hour;
+        int minute = 0;
+        try {
+            hour = Integer.parseInt(m.group(1));
+            if (m.group(3) != null) {
+                minute = Integer.parseInt(m.group(3));
             }
-            raw += minute * 60000;
-        } else if (hour >= 30 || index > 6) {
-            raw = (hour / 100 * 3600000) + (hour % 100 * 60000);
+        } catch (NumberFormatException impossible) {
+            throw new AssertionError(impossible);
         }
+
+        if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
+            return null;
+        }
+
+        char sign = id.charAt(3);
+        int raw = (hour * 3600000) + (minute * 60000);
         if (sign == '-') {
             raw = -raw;
         }
-        return new SimpleTimeZone(raw, formattedName);
-    }
 
-    private static String formatTimeZoneName(String name, int offset) {
-        StringBuilder buf = new StringBuilder();
-        int index = offset, length = name.length();
-        buf.append(name.substring(0, offset));
-
-        while (index < length) {
-            if (Character.digit(name.charAt(index), 10) != -1) {
-                buf.append(name.charAt(index));
-                if ((length - (index + 1)) == 2) {
-                    buf.append(':');
-                }
-            } else if (name.charAt(index) == ':') {
-                buf.append(':');
-            }
-            index++;
-        }
-
-        if (buf.toString().indexOf(":") == -1) {
-            buf.append(':');
-            buf.append("00");
-        }
-
-        if (buf.toString().indexOf(":") == 5) {
-            buf.insert(4, '0');
-        }
-
-        return buf.toString();
+        String cleanId = String.format("GMT%c%02d:%02d", sign, hour, minute);
+        return new SimpleTimeZone(raw, cleanId);
     }
 
     /**
@@ -380,17 +385,6 @@
      */
     public abstract boolean inDaylightTime(Date time);
 
-    private static int parseNumber(String string, int offset, int[] position) {
-        int index = offset, length = string.length(), digit, result = 0;
-        while (index < length
-                && (digit = Character.digit(string.charAt(index), 10)) != -1) {
-            index++;
-            result = result * 10 + digit;
-        }
-        position[0] = index == offset ? -1 : index;
-        return result;
-    }
-
     /**
      * Overrides the default time zone for the current process only.
      *
@@ -411,7 +405,7 @@
      */
     public void setID(String id) {
         if (id == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("id == null");
         }
         ID = id;
     }
diff --git a/luni/src/main/java/java/util/Timer.java b/luni/src/main/java/java/util/Timer.java
index b4f7a83..afc745c 100644
--- a/luni/src/main/java/java/util/Timer.java
+++ b/luni/src/main/java/java/util/Timer.java
@@ -362,7 +362,7 @@
      */
     public Timer(String name, boolean isDaemon) {
         if (name == null) {
-            throw new NullPointerException("name is null");
+            throw new NullPointerException("name == null");
         }
         this.impl = new TimerImpl(name, isDaemon);
         this.finalizer = new FinalizerHelper(impl);
diff --git a/luni/src/main/java/java/util/UUID.java b/luni/src/main/java/java/util/UUID.java
index a932bb2..8ac0a63 100644
--- a/luni/src/main/java/java/util/UUID.java
+++ b/luni/src/main/java/java/util/UUID.java
@@ -142,7 +142,7 @@
      */
     public static UUID nameUUIDFromBytes(byte[] name) {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
         try {
             MessageDigest md = MessageDigest.getInstance("MD5");
@@ -179,7 +179,7 @@
      */
     public static UUID fromString(String uuid) {
         if (uuid == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("uuid == null");
         }
 
         int[] position = new int[5];
diff --git a/luni/src/main/java/java/util/UnknownFormatConversionException.java b/luni/src/main/java/java/util/UnknownFormatConversionException.java
index e26de91..29af4e1 100644
--- a/luni/src/main/java/java/util/UnknownFormatConversionException.java
+++ b/luni/src/main/java/java/util/UnknownFormatConversionException.java
@@ -35,7 +35,7 @@
      */
     public UnknownFormatConversionException(String s) {
         if (s == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("s == null");
         }
         this.s = s;
     }
diff --git a/luni/src/main/java/java/util/UnknownFormatFlagsException.java b/luni/src/main/java/java/util/UnknownFormatFlagsException.java
index 9daa3f1..990432b 100644
--- a/luni/src/main/java/java/util/UnknownFormatFlagsException.java
+++ b/luni/src/main/java/java/util/UnknownFormatFlagsException.java
@@ -37,7 +37,7 @@
      */
     public UnknownFormatFlagsException(String f) {
         if (f == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("f == null");
         }
         flags = f;
     }
diff --git a/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java b/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java
index 36fcecc..a7f7745 100644
--- a/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java
+++ b/luni/src/main/java/java/util/concurrent/AbstractExecutorService.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java b/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
index a622832..e30ab67 100644
--- a/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/ArrayBlockingQueue.java
@@ -1,12 +1,17 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
-import java.util.concurrent.locks.*;
-import java.util.*;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.lang.ref.WeakReference;
 
 // BEGIN android-note
 // removed link to collections framework docs
@@ -73,11 +78,20 @@
 
     /** Main lock guarding all access */
     final ReentrantLock lock;
+
     /** Condition for waiting takes */
     private final Condition notEmpty;
+
     /** Condition for waiting puts */
     private final Condition notFull;
 
+    /**
+     * Shared state for currently active iterators, or null if there
+     * are known not to be any.  Allows queue operations to update
+     * iterator state.
+     */
+    transient Itrs itrs = null;
+
     // Internal helper methods
 
     /**
@@ -94,16 +108,12 @@
         return ((i == 0) ? items.length : i) - 1;
     }
 
-    @SuppressWarnings("unchecked")
-    static <E> E cast(Object item) {
-        return (E) item;
-    }
-
     /**
      * Returns item at index i.
      */
     final E itemAt(int i) {
-        return this.<E>cast(items[i]);
+        @SuppressWarnings("unchecked") E x = (E) items[i];
+        return x;
     }
 
     /**
@@ -120,10 +130,12 @@
      * Inserts element at current put position, advances, and signals.
      * Call only when holding lock.
      */
-    private void insert(E x) {
+    private void enqueue(E x) {
+        // assert lock.getHoldCount() == 1;
+        // assert items[putIndex] == null;
         items[putIndex] = x;
         putIndex = inc(putIndex);
-        ++count;
+        count++;
         notEmpty.signal();
     }
 
@@ -131,42 +143,57 @@
      * Extracts element at current take position, advances, and signals.
      * Call only when holding lock.
      */
-    private E extract() {
+    private E dequeue() {
+        // assert lock.getHoldCount() == 1;
+        // assert items[takeIndex] != null;
         final Object[] items = this.items;
-        E x = this.<E>cast(items[takeIndex]);
+        @SuppressWarnings("unchecked") E x = (E) items[takeIndex];
         items[takeIndex] = null;
         takeIndex = inc(takeIndex);
-        --count;
+        count--;
+        if (itrs != null)
+            itrs.elementDequeued();
         notFull.signal();
         return x;
     }
 
     /**
-     * Deletes item at position i.
-     * Utility for remove and iterator.remove.
+     * Deletes item at array index removeIndex.
+     * Utility for remove(Object) and iterator.remove.
      * Call only when holding lock.
      */
-    void removeAt(int i) {
+    void removeAt(final int removeIndex) {
+        // assert lock.getHoldCount() == 1;
+        // assert items[removeIndex] != null;
+        // assert removeIndex >= 0 && removeIndex < items.length;
         final Object[] items = this.items;
-        // if removing front item, just advance
-        if (i == takeIndex) {
+        if (removeIndex == takeIndex) {
+            // removing front item; just advance
             items[takeIndex] = null;
             takeIndex = inc(takeIndex);
+            count--;
+            if (itrs != null)
+                itrs.elementDequeued();
         } else {
+            // an "interior" remove
+
             // slide over all others up through putIndex.
-            for (;;) {
-                int nexti = inc(i);
-                if (nexti != putIndex) {
-                    items[i] = items[nexti];
-                    i = nexti;
+            final int putIndex = this.putIndex;
+            for (int i = removeIndex;;) {
+                int next = inc(i);
+                if (next != putIndex) {
+                    items[i] = items[next];
+                    i = next;
                 } else {
                     items[i] = null;
-                    putIndex = i;
+                    this.putIndex = i;
                     break;
                 }
             }
+            count--;
+            if (itrs != null)
+                itrs.removedAt(removeIndex);
         }
-        --count;
         notFull.signal();
     }
 
@@ -271,7 +298,7 @@
             if (count == items.length)
                 return false;
             else {
-                insert(e);
+                enqueue(e);
                 return true;
             }
         } finally {
@@ -293,7 +320,7 @@
         try {
             while (count == items.length)
                 notFull.await();
-            insert(e);
+            enqueue(e);
         } finally {
             lock.unlock();
         }
@@ -320,7 +347,7 @@
                     return false;
                 nanos = notFull.awaitNanos(nanos);
             }
-            insert(e);
+            enqueue(e);
             return true;
         } finally {
             lock.unlock();
@@ -331,7 +358,7 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            return (count == 0) ? null : extract();
+            return (count == 0) ? null : dequeue();
         } finally {
             lock.unlock();
         }
@@ -343,7 +370,7 @@
         try {
             while (count == 0)
                 notEmpty.await();
-            return extract();
+            return dequeue();
         } finally {
             lock.unlock();
         }
@@ -359,7 +386,7 @@
                     return null;
                 nanos = notEmpty.awaitNanos(nanos);
             }
-            return extract();
+            return dequeue();
         } finally {
             lock.unlock();
         }
@@ -438,11 +465,15 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) {
-                if (o.equals(items[i])) {
-                    removeAt(i);
-                    return true;
-                }
+            if (count > 0) {
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    if (o.equals(items[i])) {
+                        removeAt(i);
+                        return true;
+                    }
+                } while ((i = inc(i)) != putIndex);
             }
             return false;
         } finally {
@@ -464,9 +495,14 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
-                if (o.equals(items[i]))
-                    return true;
+            if (count > 0) {
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    if (o.equals(items[i]))
+                        return true;
+                } while ((i = inc(i)) != putIndex);
+            }
             return false;
         } finally {
             lock.unlock();
@@ -522,8 +558,7 @@
      * The following code can be used to dump the queue into a newly
      * allocated array of {@code String}:
      *
-     * <pre>
-     *     String[] y = x.toArray(new String[0]);</pre>
+     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
      *
      * Note that {@code toArray(new Object[0])} is identical in function to
      * {@code toArray()}.
@@ -589,12 +624,20 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
-                items[i] = null;
-            count = 0;
-            putIndex = 0;
-            takeIndex = 0;
-            notFull.signalAll();
+            int k = count;
+            if (k > 0) {
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    items[i] = null;
+                } while ((i = inc(i)) != putIndex);
+                takeIndex = putIndex;
+                count = 0;
+                if (itrs != null)
+                    itrs.queueIsEmpty();
+                for (; k > 0 && lock.hasWaiters(notFull); k--)
+                    notFull.signal();
+            }
         } finally {
             lock.unlock();
         }
@@ -607,32 +650,7 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c) {
-        checkNotNull(c);
-        if (c == this)
-            throw new IllegalArgumentException();
-        final Object[] items = this.items;
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try {
-            int i = takeIndex;
-            int n = 0;
-            int max = count;
-            while (n < max) {
-                c.add(this.<E>cast(items[i]));
-                items[i] = null;
-                i = inc(i);
-                ++n;
-            }
-            if (n > 0) {
-                count = 0;
-                putIndex = 0;
-                takeIndex = 0;
-                notFull.signalAll();
-            }
-            return n;
-        } finally {
-            lock.unlock();
-        }
+        return drainTo(c, Integer.MAX_VALUE);
     }
 
     /**
@@ -651,21 +669,33 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            int i = takeIndex;
-            int n = 0;
-            int max = (maxElements < count) ? maxElements : count;
-            while (n < max) {
-                c.add(this.<E>cast(items[i]));
-                items[i] = null;
-                i = inc(i);
-                ++n;
+            int n = Math.min(maxElements, count);
+            int take = takeIndex;
+            int i = 0;
+            try {
+                while (i < n) {
+                    @SuppressWarnings("unchecked") E x = (E) items[take];
+                    c.add(x);
+                    items[take] = null;
+                    take = inc(take);
+                    i++;
+                }
+                return n;
+            } finally {
+                // Restore invariants even if c.add() threw
+                if (i > 0) {
+                    count -= i;
+                    takeIndex = take;
+                    if (itrs != null) {
+                        if (count == 0)
+                            itrs.queueIsEmpty();
+                        else if (i > take)
+                            itrs.takeIndexWrapped();
+                    }
+                    for (; i > 0 && lock.hasWaiters(notFull); i--)
+                        notFull.signal();
+                }
             }
-            if (n > 0) {
-                count -= n;
-                takeIndex = i;
-                notFull.signalAll();
-            }
-            return n;
         } finally {
             lock.unlock();
         }
@@ -675,12 +705,12 @@
      * Returns an iterator over the elements in this queue in proper sequence.
      * The elements will be returned in order from first (head) to last (tail).
      *
-     * <p>The returned {@code Iterator} is a "weakly consistent" iterator that
+     * <p>The returned iterator is a "weakly consistent" iterator that
      * will never throw {@link java.util.ConcurrentModificationException
-     * ConcurrentModificationException},
-     * and guarantees to traverse elements as they existed upon
-     * construction of the iterator, and may (but is not guaranteed to)
-     * reflect any modifications subsequent to construction.
+     * ConcurrentModificationException}, and guarantees to traverse
+     * elements as they existed upon construction of the iterator, and
+     * may (but is not guaranteed to) reflect any modifications
+     * subsequent to construction.
      *
      * @return an iterator over the elements in this queue in proper sequence
      */
@@ -689,88 +719,627 @@
     }
 
     /**
-     * Iterator for ArrayBlockingQueue. To maintain weak consistency
-     * with respect to puts and takes, we (1) read ahead one slot, so
-     * as to not report hasNext true but then not have an element to
-     * return -- however we later recheck this slot to use the most
-     * current value; (2) ensure that each array slot is traversed at
-     * most once (by tracking "remaining" elements); (3) skip over
-     * null slots, which can occur if takes race ahead of iterators.
-     * However, for circular array-based queues, we cannot rely on any
-     * well established definition of what it means to be weakly
-     * consistent with respect to interior removes since these may
-     * require slot overwrites in the process of sliding elements to
-     * cover gaps. So we settle for resiliency, operating on
-     * established apparent nexts, which may miss some elements that
-     * have moved between calls to next.
+     * Shared data between iterators and their queue, allowing queue
+     * modifications to update iterators when elements are removed.
+     *
+     * This adds a lot of complexity for the sake of correctly
+     * handling some uncommon operations, but the combination of
+     * circular-arrays and supporting interior removes (i.e., those
+     * not at head) would cause iterators to sometimes lose their
+     * places and/or (re)report elements they shouldn't.  To avoid
+     * this, when a queue has one or more iterators, it keeps iterator
+     * state consistent by:
+     *
+     * (1) keeping track of the number of "cycles", that is, the
+     *     number of times takeIndex has wrapped around to 0.
+     * (2) notifying all iterators via the callback removedAt whenever
+     *     an interior element is removed (and thus other elements may
+     *     be shifted).
+     *
+     * These suffice to eliminate iterator inconsistencies, but
+     * unfortunately add the secondary responsibility of maintaining
+     * the list of iterators.  We track all active iterators in a
+     * simple linked list (accessed only when the queue's lock is
+     * held) of weak references to Itr.  The list is cleaned up using
+     * 3 different mechanisms:
+     *
+     * (1) Whenever a new iterator is created, do some O(1) checking for
+     *     stale list elements.
+     *
+     * (2) Whenever takeIndex wraps around to 0, check for iterators
+     *     that have been unused for more than one wrap-around cycle.
+     *
+     * (3) Whenever the queue becomes empty, all iterators are notified
+     *     and this entire data structure is discarded.
+     *
+     * So in addition to the removedAt callback that is necessary for
+     * correctness, iterators have the shutdown and takeIndexWrapped
+     * callbacks that help remove stale iterators from the list.
+     *
+     * Whenever a list element is examined, it is expunged if either
+     * the GC has determined that the iterator is discarded, or if the
+     * iterator reports that it is "detached" (does not need any
+     * further state updates).  Overhead is maximal when takeIndex
+     * never advances, iterators are discarded before they are
+     * exhausted, and all removals are interior removes, in which case
+     * all stale iterators are discovered by the GC.  But even in this
+     * case we don't increase the amortized complexity.
+     *
+     * Care must be taken to keep list sweeping methods from
+     * reentrantly invoking another such method, causing subtle
+     * corruption bugs.
      */
-    private class Itr implements Iterator<E> {
-        private int remaining; // Number of elements yet to be returned
-        private int nextIndex; // Index of element to be returned by next
-        private E nextItem;    // Element to be returned by next call to next
-        private E lastItem;    // Element returned by last call to next
-        private int lastRet;   // Index of last element returned, or -1 if none
+    class Itrs {
 
-        Itr() {
-            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
-            lock.lock();
-            try {
-                lastRet = -1;
-                if ((remaining = count) > 0)
-                    nextItem = itemAt(nextIndex = takeIndex);
-            } finally {
-                lock.unlock();
+        /**
+         * Node in a linked list of weak iterator references.
+         */
+        private class Node extends WeakReference<Itr> {
+            Node next;
+
+            Node(Itr iterator, Node next) {
+                super(iterator);
+                this.next = next;
             }
         }
 
-        public boolean hasNext() {
-            return remaining > 0;
+        /** Incremented whenever takeIndex wraps around to 0 */
+        int cycles = 0;
+
+        /** Linked list of weak iterator references */
+        private Node head;
+
+        /** Used to expunge stale iterators */
+        private Node sweeper = null;
+
+        private static final int SHORT_SWEEP_PROBES = 4;
+        private static final int LONG_SWEEP_PROBES = 16;
+
+        Itrs(Itr initial) {
+            register(initial);
         }
 
-        public E next() {
-            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
-            lock.lock();
-            try {
-                if (remaining <= 0)
-                    throw new NoSuchElementException();
-                lastRet = nextIndex;
-                E x = itemAt(nextIndex);  // check for fresher value
-                if (x == null) {
-                    x = nextItem;         // we are forced to report old value
-                    lastItem = null;      // but ensure remove fails
+        /**
+         * Sweeps itrs, looking for and expunging stale iterators.
+         * If at least one was found, tries harder to find more.
+         * Called only from iterating thread.
+         *
+         * @param tryHarder whether to start in try-harder mode, because
+         * there is known to be at least one iterator to collect
+         */
+        void doSomeSweeping(boolean tryHarder) {
+            // assert lock.getHoldCount() == 1;
+            // assert head != null;
+            int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
+            Node o, p;
+            final Node sweeper = this.sweeper;
+            boolean passedGo;   // to limit search to one full sweep
+
+            if (sweeper == null) {
+                o = null;
+                p = head;
+                passedGo = true;
+            } else {
+                o = sweeper;
+                p = o.next;
+                passedGo = false;
+            }
+
+            for (; probes > 0; probes--) {
+                if (p == null) {
+                    if (passedGo)
+                        break;
+                    o = null;
+                    p = head;
+                    passedGo = true;
                 }
-                else
-                    lastItem = x;
-                while (--remaining > 0 && // skip over nulls
-                       (nextItem = itemAt(nextIndex = inc(nextIndex))) == null)
-                    ;
-                return x;
-            } finally {
-                lock.unlock();
+                final Itr it = p.get();
+                final Node next = p.next;
+                if (it == null || it.isDetached()) {
+                    // found a discarded/exhausted iterator
+                    probes = LONG_SWEEP_PROBES; // "try harder"
+                    // unlink p
+                    p.clear();
+                    p.next = null;
+                    if (o == null) {
+                        head = next;
+                        if (next == null) {
+                            // We've run out of iterators to track; retire
+                            itrs = null;
+                            return;
+                        }
+                    }
+                    else
+                        o.next = next;
+                } else {
+                    o = p;
+                }
+                p = next;
             }
+
+            this.sweeper = (p == null) ? null : o;
         }
 
-        public void remove() {
-            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
-            lock.lock();
-            try {
-                int i = lastRet;
-                if (i == -1)
-                    throw new IllegalStateException();
-                lastRet = -1;
-                E x = lastItem;
-                lastItem = null;
-                // only remove if item still at index
-                if (x != null && x == items[i]) {
-                    boolean removingHead = (i == takeIndex);
-                    removeAt(i);
-                    if (!removingHead)
-                        nextIndex = dec(nextIndex);
+        /**
+         * Adds a new iterator to the linked list of tracked iterators.
+         */
+        void register(Itr itr) {
+            // assert lock.getHoldCount() == 1;
+            head = new Node(itr, head);
+        }
+
+        /**
+         * Called whenever takeIndex wraps around to 0.
+         *
+         * Notifies all iterators, and expunges any that are now stale.
+         */
+        void takeIndexWrapped() {
+            // assert lock.getHoldCount() == 1;
+            cycles++;
+            for (Node o = null, p = head; p != null;) {
+                final Itr it = p.get();
+                final Node next = p.next;
+                if (it == null || it.takeIndexWrapped()) {
+                    // unlink p
+                    // assert it == null || it.isDetached();
+                    p.clear();
+                    p.next = null;
+                    if (o == null)
+                        head = next;
+                    else
+                        o.next = next;
+                } else {
+                    o = p;
                 }
-            } finally {
-                lock.unlock();
+                p = next;
             }
+            if (head == null)   // no more iterators to track
+                itrs = null;
+        }
+
+        /**
+         * Called whenever an interior remove (not at takeIndex) occured.
+         *
+         * Notifies all iterators, and expunges any that are now stale.
+         */
+        void removedAt(int removedIndex) {
+            for (Node o = null, p = head; p != null;) {
+                final Itr it = p.get();
+                final Node next = p.next;
+                if (it == null || it.removedAt(removedIndex)) {
+                    // unlink p
+                    // assert it == null || it.isDetached();
+                    p.clear();
+                    p.next = null;
+                    if (o == null)
+                        head = next;
+                    else
+                        o.next = next;
+                } else {
+                    o = p;
+                }
+                p = next;
+            }
+            if (head == null)   // no more iterators to track
+                itrs = null;
+        }
+
+        /**
+         * Called whenever the queue becomes empty.
+         *
+         * Notifies all active iterators that the queue is empty,
+         * clears all weak refs, and unlinks the itrs datastructure.
+         */
+        void queueIsEmpty() {
+            // assert lock.getHoldCount() == 1;
+            for (Node p = head; p != null; p = p.next) {
+                Itr it = p.get();
+                if (it != null) {
+                    p.clear();
+                    it.shutdown();
+                }
+            }
+            head = null;
+            itrs = null;
+        }
+
+        /**
+         * Called whenever an element has been dequeued (at takeIndex).
+         */
+        void elementDequeued() {
+            // assert lock.getHoldCount() == 1;
+            if (count == 0)
+                queueIsEmpty();
+            else if (takeIndex == 0)
+                takeIndexWrapped();
         }
     }
 
+    /**
+     * Iterator for ArrayBlockingQueue.
+     *
+     * To maintain weak consistency with respect to puts and takes, we
+     * read ahead one slot, so as to not report hasNext true but then
+     * not have an element to return.
+     *
+     * We switch into "detached" mode (allowing prompt unlinking from
+     * itrs without help from the GC) when all indices are negative, or
+     * when hasNext returns false for the first time.  This allows the
+     * iterator to track concurrent updates completely accurately,
+     * except for the corner case of the user calling Iterator.remove()
+     * after hasNext() returned false.  Even in this case, we ensure
+     * that we don't remove the wrong element by keeping track of the
+     * expected element to remove, in lastItem.  Yes, we may fail to
+     * remove lastItem from the queue if it moved due to an interleaved
+     * interior remove while in detached mode.
+     */
+    private class Itr implements Iterator<E> {
+        /** Index to look for new nextItem; NONE at end */
+        private int cursor;
+
+        /** Element to be returned by next call to next(); null if none */
+        private E nextItem;
+
+        /** Index of nextItem; NONE if none, REMOVED if removed elsewhere */
+        private int nextIndex;
+
+        /** Last element returned; null if none or not detached. */
+        private E lastItem;
+
+        /** Index of lastItem, NONE if none, REMOVED if removed elsewhere */
+        private int lastRet;
+
+        /** Previous value of takeIndex, or DETACHED when detached */
+        private int prevTakeIndex;
+
+        /** Previous value of iters.cycles */
+        private int prevCycles;
+
+        /** Special index value indicating "not available" or "undefined" */
+        private static final int NONE = -1;
+
+        /**
+         * Special index value indicating "removed elsewhere", that is,
+         * removed by some operation other than a call to this.remove().
+         */
+        private static final int REMOVED = -2;
+
+        /** Special value for prevTakeIndex indicating "detached mode" */
+        private static final int DETACHED = -3;
+
+        Itr() {
+            // assert lock.getHoldCount() == 0;
+            lastRet = NONE;
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (count == 0) {
+                    // assert itrs == null;
+                    cursor = NONE;
+                    nextIndex = NONE;
+                    prevTakeIndex = DETACHED;
+                } else {
+                    final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+                    prevTakeIndex = takeIndex;
+                    nextItem = itemAt(nextIndex = takeIndex);
+                    cursor = incCursor(takeIndex);
+                    if (itrs == null) {
+                        itrs = new Itrs(this);
+                    } else {
+                        itrs.register(this); // in this order
+                        itrs.doSomeSweeping(false);
+                    }
+                    prevCycles = itrs.cycles;
+                    // assert takeIndex >= 0;
+                    // assert prevTakeIndex == takeIndex;
+                    // assert nextIndex >= 0;
+                    // assert nextItem != null;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        boolean isDetached() {
+            // assert lock.getHoldCount() == 1;
+            return prevTakeIndex < 0;
+        }
+
+        private int incCursor(int index) {
+            // assert lock.getHoldCount() == 1;
+            index = inc(index);
+            if (index == putIndex)
+                index = NONE;
+            return index;
+        }
+
+        /**
+         * Returns true if index is invalidated by the given number of
+         * dequeues, starting from prevTakeIndex.
+         */
+        private boolean invalidated(int index, int prevTakeIndex,
+                                    long dequeues, int length) {
+            if (index < 0)
+                return false;
+            int distance = index - prevTakeIndex;
+            if (distance < 0)
+                distance += length;
+            return dequeues > distance;
+        }
+
+        /**
+         * Adjusts indices to incorporate all dequeues since the last
+         * operation on this iterator.  Call only from iterating thread.
+         */
+        private void incorporateDequeues() {
+            // assert lock.getHoldCount() == 1;
+            // assert itrs != null;
+            // assert !isDetached();
+            // assert count > 0;
+
+            final int cycles = itrs.cycles;
+            final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+            final int prevCycles = this.prevCycles;
+            final int prevTakeIndex = this.prevTakeIndex;
+
+            if (cycles != prevCycles || takeIndex != prevTakeIndex) {
+                final int len = items.length;
+                // how far takeIndex has advanced since the previous
+                // operation of this iterator
+                long dequeues = (cycles - prevCycles) * len
+                    + (takeIndex - prevTakeIndex);
+
+                // Check indices for invalidation
+                if (invalidated(lastRet, prevTakeIndex, dequeues, len))
+                    lastRet = REMOVED;
+                if (invalidated(nextIndex, prevTakeIndex, dequeues, len))
+                    nextIndex = REMOVED;
+                if (invalidated(cursor, prevTakeIndex, dequeues, len))
+                    cursor = takeIndex;
+
+                if (cursor < 0 && nextIndex < 0 && lastRet < 0)
+                    detach();
+                else {
+                    this.prevCycles = cycles;
+                    this.prevTakeIndex = takeIndex;
+                }
+            }
+        }
+
+        /**
+         * Called when itrs should stop tracking this iterator, either
+         * because there are no more indices to update (cursor < 0 &&
+         * nextIndex < 0 && lastRet < 0) or as a special exception, when
+         * lastRet >= 0, because hasNext() is about to return false for the
+         * first time.  Call only from iterating thread.
+         */
+        private void detach() {
+            // Switch to detached mode
+            // assert lock.getHoldCount() == 1;
+            // assert cursor == NONE;
+            // assert nextIndex < 0;
+            // assert lastRet < 0 || nextItem == null;
+            // assert lastRet < 0 ^ lastItem != null;
+            if (prevTakeIndex >= 0) {
+                // assert itrs != null;
+                prevTakeIndex = DETACHED;
+                // try to unlink from itrs (but not too hard)
+                itrs.doSomeSweeping(true);
+            }
+        }
+
+        /**
+         * For performance reasons, we would like not to acquire a lock in
+         * hasNext in the common case.  To allow for this, we only access
+         * fields (i.e. nextItem) that are not modified by update operations
+         * triggered by queue modifications.
+         */
+        public boolean hasNext() {
+            // assert lock.getHoldCount() == 0;
+            if (nextItem != null)
+                return true;
+            noNext();
+            return false;
+        }
+
+        private void noNext() {
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                // assert cursor == NONE;
+                // assert nextIndex == NONE;
+                if (!isDetached()) {
+                    // assert lastRet >= 0;
+                    incorporateDequeues(); // might update lastRet
+                    if (lastRet >= 0) {
+                        lastItem = itemAt(lastRet);
+                        // assert lastItem != null;
+                        detach();
+                    }
+                }
+                // assert isDetached();
+                // assert lastRet < 0 ^ lastItem != null;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public E next() {
+            // assert lock.getHoldCount() == 0;
+            final E x = nextItem;
+            if (x == null)
+                throw new NoSuchElementException();
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (!isDetached())
+                    incorporateDequeues();
+                // assert nextIndex != NONE;
+                // assert lastItem == null;
+                lastRet = nextIndex;
+                final int cursor = this.cursor;
+                if (cursor >= 0) {
+                    nextItem = itemAt(nextIndex = cursor);
+                    // assert nextItem != null;
+                    this.cursor = incCursor(cursor);
+                } else {
+                    nextIndex = NONE;
+                    nextItem = null;
+                }
+            } finally {
+                lock.unlock();
+            }
+            return x;
+        }
+
+        public void remove() {
+            // assert lock.getHoldCount() == 0;
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (!isDetached())
+                    incorporateDequeues(); // might update lastRet or detach
+                final int lastRet = this.lastRet;
+                this.lastRet = NONE;
+                if (lastRet >= 0) {
+                    if (!isDetached())
+                        removeAt(lastRet);
+                    else {
+                        final E lastItem = this.lastItem;
+                        // assert lastItem != null;
+                        this.lastItem = null;
+                        if (itemAt(lastRet) == lastItem)
+                            removeAt(lastRet);
+                    }
+                } else if (lastRet == NONE)
+                    throw new IllegalStateException();
+                // else lastRet == REMOVED and the last returned element was
+                // previously asynchronously removed via an operation other
+                // than this.remove(), so nothing to do.
+
+                if (cursor < 0 && nextIndex < 0)
+                    detach();
+            } finally {
+                lock.unlock();
+                // assert lastRet == NONE;
+                // assert lastItem == null;
+            }
+        }
+
+        /**
+         * Called to notify the iterator that the queue is empty, or that it
+         * has fallen hopelessly behind, so that it should abandon any
+         * further iteration, except possibly to return one more element
+         * from next(), as promised by returning true from hasNext().
+         */
+        void shutdown() {
+            // assert lock.getHoldCount() == 1;
+            cursor = NONE;
+            if (nextIndex >= 0)
+                nextIndex = REMOVED;
+            if (lastRet >= 0) {
+                lastRet = REMOVED;
+                lastItem = null;
+            }
+            prevTakeIndex = DETACHED;
+            // Don't set nextItem to null because we must continue to be
+            // able to return it on next().
+            //
+            // Caller will unlink from itrs when convenient.
+        }
+
+        private int distance(int index, int prevTakeIndex, int length) {
+            int distance = index - prevTakeIndex;
+            if (distance < 0)
+                distance += length;
+            return distance;
+        }
+
+        /**
+         * Called whenever an interior remove (not at takeIndex) occured.
+         *
+         * @return true if this iterator should be unlinked from itrs
+         */
+        boolean removedAt(int removedIndex) {
+            // assert lock.getHoldCount() == 1;
+            if (isDetached())
+                return true;
+
+            final int cycles = itrs.cycles;
+            final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+            final int prevCycles = this.prevCycles;
+            final int prevTakeIndex = this.prevTakeIndex;
+            final int len = items.length;
+            int cycleDiff = cycles - prevCycles;
+            if (removedIndex < takeIndex)
+                cycleDiff++;
+            final int removedDistance =
+                (cycleDiff * len) + (removedIndex - prevTakeIndex);
+            // assert removedDistance >= 0;
+            int cursor = this.cursor;
+            if (cursor >= 0) {
+                int x = distance(cursor, prevTakeIndex, len);
+                if (x == removedDistance) {
+                    if (cursor == putIndex)
+                        this.cursor = cursor = NONE;
+                }
+                else if (x > removedDistance) {
+                    // assert cursor != prevTakeIndex;
+                    this.cursor = cursor = dec(cursor);
+                }
+            }
+            int lastRet = this.lastRet;
+            if (lastRet >= 0) {
+                int x = distance(lastRet, prevTakeIndex, len);
+                if (x == removedDistance)
+                    this.lastRet = lastRet = REMOVED;
+                else if (x > removedDistance)
+                    this.lastRet = lastRet = dec(lastRet);
+            }
+            int nextIndex = this.nextIndex;
+            if (nextIndex >= 0) {
+                int x = distance(nextIndex, prevTakeIndex, len);
+                if (x == removedDistance)
+                    this.nextIndex = nextIndex = REMOVED;
+                else if (x > removedDistance)
+                    this.nextIndex = nextIndex = dec(nextIndex);
+            }
+            else if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
+                this.prevTakeIndex = DETACHED;
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Called whenever takeIndex wraps around to zero.
+         *
+         * @return true if this iterator should be unlinked from itrs
+         */
+        boolean takeIndexWrapped() {
+            // assert lock.getHoldCount() == 1;
+            if (isDetached())
+                return true;
+            if (itrs.cycles - prevCycles > 1) {
+                // All the elements that existed at the time of the last
+                // operation are gone, so abandon further iteration.
+                shutdown();
+                return true;
+            }
+            return false;
+        }
+
+//         /** Uncomment for debugging. */
+//         public String toString() {
+//             return ("cursor=" + cursor + " " +
+//                     "nextIndex=" + nextIndex + " " +
+//                     "lastRet=" + lastRet + " " +
+//                     "nextItem=" + nextItem + " " +
+//                     "lastItem=" + lastItem + " " +
+//                     "prevCycles=" + prevCycles + " " +
+//                     "prevTakeIndex=" + prevTakeIndex + " " +
+//                     "size()=" + size() + " " +
+//                     "remainingCapacity()=" + remainingCapacity());
+//         }
+    }
 }
diff --git a/luni/src/main/java/java/util/concurrent/BlockingDeque.java b/luni/src/main/java/java/util/concurrent/BlockingDeque.java
index 136df9c..34f103d 100644
--- a/luni/src/main/java/java/util/concurrent/BlockingDeque.java
+++ b/luni/src/main/java/java/util/concurrent/BlockingDeque.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -36,9 +36,9 @@
  *  <tr>
  *    <td><b>Insert</b></td>
  *    <td>{@link #addFirst addFirst(e)}</td>
- *    <td>{@link #offerFirst offerFirst(e)}</td>
+ *    <td>{@link #offerFirst(Object) offerFirst(e)}</td>
  *    <td>{@link #putFirst putFirst(e)}</td>
- *    <td>{@link #offerFirst offerFirst(e, time, unit)}</td>
+ *    <td>{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
  *  </tr>
  *  <tr>
  *    <td><b>Remove</b></td>
@@ -67,9 +67,9 @@
  *  <tr>
  *    <td><b>Insert</b></td>
  *    <td>{@link #addLast addLast(e)}</td>
- *    <td>{@link #offerLast offerLast(e)}</td>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
  *    <td>{@link #putLast putLast(e)}</td>
- *    <td>{@link #offerLast offerLast(e, time, unit)}</td>
+ *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
  *  </tr>
  *  <tr>
  *    <td><b>Remove</b></td>
@@ -106,20 +106,20 @@
  *    <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>
  *  </tr>
  *  <tr>
- *    <td>{@link #add add(e)}</td>
- *    <td>{@link #addLast addLast(e)}</td>
+ *    <td>{@link #add(Object) add(e)}</td>
+ *    <td>{@link #addLast(Object) addLast(e)}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #offer offer(e)}</td>
- *    <td>{@link #offerLast offerLast(e)}</td>
+ *    <td>{@link #offer(Object) offer(e)}</td>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #put put(e)}</td>
- *    <td>{@link #putLast putLast(e)}</td>
+ *    <td>{@link #put(Object) put(e)}</td>
+ *    <td>{@link #putLast(Object) putLast(e)}</td>
  *  </tr>
  *  <tr>
- *    <td>{@link #offer offer(e, time, unit)}</td>
- *    <td>{@link #offerLast offerLast(e, time, unit)}</td>
+ *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
+ *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
  *  </tr>
  *  <tr>
  *    <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td>
@@ -181,7 +181,7 @@
      * possible to do so immediately without violating capacity restrictions,
      * throwing an <tt>IllegalStateException</tt> if no space is currently
      * available.  When using a capacity-restricted deque, it is generally
-     * preferable to use {@link #offerFirst offerFirst}.
+     * preferable to use {@link #offerFirst(Object) offerFirst}.
      *
      * @param e the element to add
      * @throws IllegalStateException {@inheritDoc}
@@ -196,7 +196,7 @@
      * possible to do so immediately without violating capacity restrictions,
      * throwing an <tt>IllegalStateException</tt> if no space is currently
      * available.  When using a capacity-restricted deque, it is generally
-     * preferable to use {@link #offerLast offerLast}.
+     * preferable to use {@link #offerLast(Object) offerLast}.
      *
      * @param e the element to add
      * @throws IllegalStateException {@inheritDoc}
@@ -212,7 +212,7 @@
      * returning <tt>true</tt> upon success and <tt>false</tt> if no space is
      * currently available.
      * When using a capacity-restricted deque, this method is generally
-     * preferable to the {@link #addFirst addFirst} method, which can
+     * preferable to the {@link #addFirst(Object) addFirst} method, which can
      * fail to insert an element only by throwing an exception.
      *
      * @param e the element to add
@@ -228,7 +228,7 @@
      * returning <tt>true</tt> upon success and <tt>false</tt> if no space is
      * currently available.
      * When using a capacity-restricted deque, this method is generally
-     * preferable to the {@link #addLast addLast} method, which can
+     * preferable to the {@link #addLast(Object) addLast} method, which can
      * fail to insert an element only by throwing an exception.
      *
      * @param e the element to add
@@ -371,8 +371,10 @@
      * @param o element to be removed from this deque, if present
      * @return <tt>true</tt> if an element was removed as a result of this call
      * @throws ClassCastException if the class of the specified element
-     *         is incompatible with this deque (optional)
-     * @throws NullPointerException if the specified element is null (optional)
+     *         is incompatible with this deque
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean removeFirstOccurrence(Object o);
 
@@ -387,8 +389,10 @@
      * @param o element to be removed from this deque, if present
      * @return <tt>true</tt> if an element was removed as a result of this call
      * @throws ClassCastException if the class of the specified element
-     *         is incompatible with this deque (optional)
-     * @throws NullPointerException if the specified element is null (optional)
+     *         is incompatible with this deque
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean removeLastOccurrence(Object o);
 
@@ -401,9 +405,9 @@
      * <tt>true</tt> upon success and throwing an
      * <tt>IllegalStateException</tt> if no space is currently available.
      * When using a capacity-restricted deque, it is generally preferable to
-     * use {@link #offer offer}.
+     * use {@link #offer(Object) offer}.
      *
-     * <p>This method is equivalent to {@link #addLast addLast}.
+     * <p>This method is equivalent to {@link #addLast(Object) addLast}.
      *
      * @param e the element to add
      * @throws IllegalStateException {@inheritDoc}
@@ -424,7 +428,7 @@
      * generally preferable to the {@link #add} method, which can fail to
      * insert an element only by throwing an exception.
      *
-     * <p>This method is equivalent to {@link #offerLast offerLast}.
+     * <p>This method is equivalent to {@link #offerLast(Object) offerLast}.
      *
      * @param e the element to add
      * @throws ClassCastException if the class of the specified element
@@ -440,7 +444,7 @@
      * (in other words, at the tail of this deque), waiting if necessary for
      * space to become available.
      *
-     * <p>This method is equivalent to {@link #putLast putLast}.
+     * <p>This method is equivalent to {@link #putLast(Object) putLast}.
      *
      * @param e the element to add
      * @throws InterruptedException {@inheritDoc}
@@ -458,7 +462,7 @@
      * specified wait time if necessary for space to become available.
      *
      * <p>This method is equivalent to
-     * {@link #offerLast offerLast}.
+     * {@link #offerLast(Object,long,TimeUnit) offerLast}.
      *
      * @param e the element to add
      * @return <tt>true</tt> if the element was added to this deque, else
@@ -557,13 +561,15 @@
      * (or equivalently, if this deque changed as a result of the call).
      *
      * <p>This method is equivalent to
-     * {@link #removeFirstOccurrence removeFirstOccurrence}.
+     * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
      *
      * @param o element to be removed from this deque, if present
      * @return <tt>true</tt> if this deque changed as a result of the call
      * @throws ClassCastException if the class of the specified element
-     *         is incompatible with this deque (optional)
-     * @throws NullPointerException if the specified element is null (optional)
+     *         is incompatible with this deque
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean remove(Object o);
 
@@ -575,8 +581,10 @@
      * @param o object to be checked for containment in this deque
      * @return <tt>true</tt> if this deque contains the specified element
      * @throws ClassCastException if the class of the specified element
-     *         is incompatible with this deque (optional)
-     * @throws NullPointerException if the specified element is null (optional)
+     *         is incompatible with this deque
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     public boolean contains(Object o);
 
@@ -602,7 +610,7 @@
      * words, inserts the element at the front of this deque unless it would
      * violate capacity restrictions.
      *
-     * <p>This method is equivalent to {@link #addFirst addFirst}.
+     * <p>This method is equivalent to {@link #addFirst(Object) addFirst}.
      *
      * @throws IllegalStateException {@inheritDoc}
      * @throws ClassCastException {@inheritDoc}
diff --git a/luni/src/main/java/java/util/concurrent/BlockingQueue.java b/luni/src/main/java/java/util/concurrent/BlockingQueue.java
index d01c097..6cfe52b 100644
--- a/luni/src/main/java/java/util/concurrent/BlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/BlockingQueue.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -42,7 +42,7 @@
  *    <td>{@link #add add(e)}</td>
  *    <td>{@link #offer offer(e)}</td>
  *    <td>{@link #put put(e)}</td>
- *    <td>{@link #offer offer(e, time, unit)}</td>
+ *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
  *  </tr>
  *  <tr>
  *    <td><b>Remove</b></td>
@@ -102,7 +102,7 @@
  * Usage example, based on a typical producer-consumer scenario.
  * Note that a <tt>BlockingQueue</tt> can safely be used with multiple
  * producers and multiple consumers.
- * <pre>
+ *  <pre> {@code
  * class Producer implements Runnable {
  *   private final BlockingQueue queue;
  *   Producer(BlockingQueue q) { queue = q; }
@@ -135,8 +135,7 @@
  *     new Thread(c1).start();
  *     new Thread(c2).start();
  *   }
- * }
- * </pre>
+ * }}</pre>
  *
  * <p>Memory consistency effects: As with other concurrent
  * collections, actions in a thread prior to placing an object into a
@@ -156,7 +155,7 @@
      * <tt>true</tt> upon success and throwing an
      * <tt>IllegalStateException</tt> if no space is currently available.
      * When using a capacity-restricted queue, it is generally preferable to
-     * use {@link #offer offer}.
+     * use {@link #offer(Object) offer}.
      *
      * @param e the element to add
      * @return <tt>true</tt> (as specified by {@link Collection#add})
@@ -274,8 +273,10 @@
      * @param o element to be removed from this queue, if present
      * @return <tt>true</tt> if this queue changed as a result of the call
      * @throws ClassCastException if the class of the specified element
-     *         is incompatible with this queue (optional)
-     * @throws NullPointerException if the specified element is null (optional)
+     *         is incompatible with this queue
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean remove(Object o);
 
@@ -287,8 +288,10 @@
      * @param o object to be checked for containment in this queue
      * @return <tt>true</tt> if this queue contains the specified element
      * @throws ClassCastException if the class of the specified element
-     *         is incompatible with this queue (optional)
-     * @throws NullPointerException if the specified element is null (optional)
+     *         is incompatible with this queue
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     public boolean contains(Object o);
 
diff --git a/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java b/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java
index 3f93fbb..76fae13 100644
--- a/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java
+++ b/luni/src/main/java/java/util/concurrent/BrokenBarrierException.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/Callable.java b/luni/src/main/java/java/util/concurrent/Callable.java
index abc4d04..293544b 100644
--- a/luni/src/main/java/java/util/concurrent/Callable.java
+++ b/luni/src/main/java/java/util/concurrent/Callable.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/CancellationException.java b/luni/src/main/java/java/util/concurrent/CancellationException.java
index 2c29544..dc452e4 100644
--- a/luni/src/main/java/java/util/concurrent/CancellationException.java
+++ b/luni/src/main/java/java/util/concurrent/CancellationException.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/CompletionService.java b/luni/src/main/java/java/util/concurrent/CompletionService.java
index df9f719..7b0931c 100644
--- a/luni/src/main/java/java/util/concurrent/CompletionService.java
+++ b/luni/src/main/java/java/util/concurrent/CompletionService.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
index c142e2a..c85a5cc 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
@@ -1,16 +1,13 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
 import java.util.concurrent.locks.*;
 import java.util.*;
 import java.io.Serializable;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
 
 // BEGIN android-note
 // removed link to collections framework docs
@@ -76,7 +73,25 @@
 
     /*
      * The basic strategy is to subdivide the table among Segments,
-     * each of which itself is a concurrently readable hash table.
+     * each of which itself is a concurrently readable hash table.  To
+     * reduce footprint, all but one segments are constructed only
+     * when first needed (see ensureSegment). To maintain visibility
+     * in the presence of lazy construction, accesses to segments as
+     * well as elements of segment's table must use volatile access,
+     * which is done via Unsafe within methods segmentAt etc
+     * below. These provide the functionality of AtomicReferenceArrays
+     * but reduce the levels of indirection. Additionally,
+     * volatile-writes of table elements and entry "next" fields
+     * within locked operations use the cheaper "lazySet" forms of
+     * writes (via putOrderedObject) because these writes are always
+     * followed by lock releases that maintain sequential consistency
+     * of table updates.
+     *
+     * Historical note: The previous version of this class relied
+     * heavily on "final" fields, which avoided some volatile reads at
+     * the expense of a large initial footprint.  Some remnants of
+     * that design (including forced construction of segment 0) exist
+     * to ensure serialization compatibility.
      */
 
     /* ---------------- Constants -------------- */
@@ -108,8 +123,15 @@
     static final int MAXIMUM_CAPACITY = 1 << 30;
 
     /**
+     * The minimum capacity for per-segment tables.  Must be a power
+     * of two, at least two to avoid immediate resizing on next use
+     * after lazy construction.
+     */
+    static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
+
+    /**
      * The maximum number of segments to allow; used to bound
-     * constructor arguments.
+     * constructor arguments. Must be power of two less than 1 << 24.
      */
     static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
 
@@ -135,7 +157,7 @@
     final int segmentShift;
 
     /**
-     * The segments, each of which is a specialized hash table
+     * The segments, each of which is a specialized hash table.
      */
     final Segment<K,V>[] segments;
 
@@ -143,7 +165,66 @@
     transient Set<Map.Entry<K,V>> entrySet;
     transient Collection<V> values;
 
-    /* ---------------- Small Utilities -------------- */
+    /**
+     * ConcurrentHashMap list entry. Note that this is never exported
+     * out as a user-visible Map.Entry.
+     */
+    static final class HashEntry<K,V> {
+        final int hash;
+        final K key;
+        volatile V value;
+        volatile HashEntry<K,V> next;
+
+        HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
+            this.hash = hash;
+            this.key = key;
+            this.value = value;
+            this.next = next;
+        }
+
+        /**
+         * Sets next field with volatile write semantics.  (See above
+         * about use of putOrderedObject.)
+         */
+        final void setNext(HashEntry<K,V> n) {
+            UNSAFE.putOrderedObject(this, nextOffset, n);
+        }
+
+        // Unsafe mechanics
+        static final sun.misc.Unsafe UNSAFE;
+        static final long nextOffset;
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class<?> k = HashEntry.class;
+                nextOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("next"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /**
+     * Gets the ith element of given table (if nonnull) with volatile
+     * read semantics. Note: This is manually integrated into a few
+     * performance-sensitive methods to reduce call overhead.
+     */
+    @SuppressWarnings("unchecked")
+    static final <K,V> HashEntry<K,V> entryAt(HashEntry<K,V>[] tab, int i) {
+        return (tab == null) ? null :
+            (HashEntry<K,V>) UNSAFE.getObjectVolatile
+            (tab, ((long)i << TSHIFT) + TBASE);
+    }
+
+    /**
+     * Sets the ith element of given table, with volatile write
+     * semantics. (See above about use of putOrderedObject.)
+     */
+    static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
+                                       HashEntry<K,V> e) {
+        UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
+    }
 
     /**
      * Applies a supplemental hash function to a given hashCode, which
@@ -164,104 +245,67 @@
     }
 
     /**
-     * Returns the segment that should be used for key with given hash
-     * @param hash the hash code for the key
-     * @return the segment
-     */
-    final Segment<K,V> segmentFor(int hash) {
-        return segments[(hash >>> segmentShift) & segmentMask];
-    }
-
-    /* ---------------- Inner Classes -------------- */
-
-    /**
-     * ConcurrentHashMap list entry. Note that this is never exported
-     * out as a user-visible Map.Entry.
-     *
-     * Because the value field is volatile, not final, it is legal wrt
-     * the Java Memory Model for an unsynchronized reader to see null
-     * instead of initial value when read via a data race.  Although a
-     * reordering leading to this is not likely to ever actually
-     * occur, the Segment.readValueUnderLock method is used as a
-     * backup in case a null (pre-initialized) value is ever seen in
-     * an unsynchronized access method.
-     */
-    static final class HashEntry<K,V> {
-        final K key;
-        final int hash;
-        volatile V value;
-        final HashEntry<K,V> next;
-
-        HashEntry(K key, int hash, HashEntry<K,V> next, V value) {
-            this.key = key;
-            this.hash = hash;
-            this.next = next;
-            this.value = value;
-        }
-
-        @SuppressWarnings("unchecked")
-        static final <K,V> HashEntry<K,V>[] newArray(int i) {
-            return new HashEntry[i];
-        }
-    }
-
-    /**
      * Segments are specialized versions of hash tables.  This
      * subclasses from ReentrantLock opportunistically, just to
      * simplify some locking and avoid separate construction.
      */
     static final class Segment<K,V> extends ReentrantLock implements Serializable {
         /*
-         * Segments maintain a table of entry lists that are ALWAYS
-         * kept in a consistent state, so can be read without locking.
-         * Next fields of nodes are immutable (final).  All list
-         * additions are performed at the front of each bin. This
-         * makes it easy to check changes, and also fast to traverse.
-         * When nodes would otherwise be changed, new nodes are
-         * created to replace them. This works well for hash tables
-         * since the bin lists tend to be short. (The average length
-         * is less than two for the default load factor threshold.)
+         * Segments maintain a table of entry lists that are always
+         * kept in a consistent state, so can be read (via volatile
+         * reads of segments and tables) without locking.  This
+         * requires replicating nodes when necessary during table
+         * resizing, so the old lists can be traversed by readers
+         * still using old version of table.
          *
-         * Read operations can thus proceed without locking, but rely
-         * on selected uses of volatiles to ensure that completed
-         * write operations performed by other threads are
-         * noticed. For most purposes, the "count" field, tracking the
-         * number of elements, serves as that volatile variable
-         * ensuring visibility.  This is convenient because this field
-         * needs to be read in many read operations anyway:
-         *
-         *   - All (unsynchronized) read operations must first read the
-         *     "count" field, and should not look at table entries if
-         *     it is 0.
-         *
-         *   - All (synchronized) write operations should write to
-         *     the "count" field after structurally changing any bin.
-         *     The operations must not take any action that could even
-         *     momentarily cause a concurrent read operation to see
-         *     inconsistent data. This is made easier by the nature of
-         *     the read operations in Map. For example, no operation
-         *     can reveal that the table has grown but the threshold
-         *     has not yet been updated, so there are no atomicity
-         *     requirements for this with respect to reads.
-         *
-         * As a guide, all critical volatile reads and writes to the
-         * count field are marked in code comments.
+         * This class defines only mutative methods requiring locking.
+         * Except as noted, the methods of this class perform the
+         * per-segment versions of ConcurrentHashMap methods.  (Other
+         * methods are integrated directly into ConcurrentHashMap
+         * methods.) These mutative methods use a form of controlled
+         * spinning on contention via methods scanAndLock and
+         * scanAndLockForPut. These intersperse tryLocks with
+         * traversals to locate nodes.  The main benefit is to absorb
+         * cache misses (which are very common for hash tables) while
+         * obtaining locks so that traversal is faster once
+         * acquired. We do not actually use the found nodes since they
+         * must be re-acquired under lock anyway to ensure sequential
+         * consistency of updates (and in any case may be undetectably
+         * stale), but they will normally be much faster to re-locate.
+         * Also, scanAndLockForPut speculatively creates a fresh node
+         * to use in put if no node is found.
          */
 
         private static final long serialVersionUID = 2249069246763182397L;
 
         /**
-         * The number of elements in this segment's region.
+         * The maximum number of times to tryLock in a prescan before
+         * possibly blocking on acquire in preparation for a locked
+         * segment operation. On multiprocessors, using a bounded
+         * number of retries maintains cache acquired while locating
+         * nodes.
          */
-        transient volatile int count;
+        static final int MAX_SCAN_RETRIES =
+            Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
 
         /**
-         * Number of updates that alter the size of the table. This is
-         * used during bulk-read methods to make sure they see a
-         * consistent snapshot: If modCounts change during a traversal
-         * of segments computing size or checking containsValue, then
-         * we might have an inconsistent view of state so (usually)
-         * must retry.
+         * The per-segment table. Elements are accessed via
+         * entryAt/setEntryAt providing volatile semantics.
+         */
+        transient volatile HashEntry<K,V>[] table;
+
+        /**
+         * The number of elements. Accessed only either within locks
+         * or among other volatile reads that maintain visibility.
+         */
+        transient int count;
+
+        /**
+         * The total number of mutative operations in this segment.
+         * Even though this may overflows 32 bits, it provides
+         * sufficient accuracy for stability checks in CHM isEmpty()
+         * and size() methods.  Accessed only either within locks or
+         * among other volatile reads that maintain visibility.
          */
         transient int modCount;
 
@@ -273,11 +317,6 @@
         transient int threshold;
 
         /**
-         * The per-segment table.
-         */
-        transient volatile HashEntry<K,V>[] table;
-
-        /**
          * The load factor for the hash table.  Even though this value
          * is same for all segments, it is replicated to avoid needing
          * links to outer object.
@@ -285,202 +324,93 @@
          */
         final float loadFactor;
 
-        Segment(int initialCapacity, float lf) {
-            loadFactor = lf;
-            setTable(HashEntry.<K,V>newArray(initialCapacity));
+        Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
+            this.loadFactor = lf;
+            this.threshold = threshold;
+            this.table = tab;
         }
 
+        final V put(K key, int hash, V value, boolean onlyIfAbsent) {
+            HashEntry<K,V> node = tryLock() ? null :
+                scanAndLockForPut(key, hash, value);
+            V oldValue;
+            try {
+                HashEntry<K,V>[] tab = table;
+                int index = (tab.length - 1) & hash;
+                HashEntry<K,V> first = entryAt(tab, index);
+                for (HashEntry<K,V> e = first;;) {
+                    if (e != null) {
+                        K k;
+                        if ((k = e.key) == key ||
+                            (e.hash == hash && key.equals(k))) {
+                            oldValue = e.value;
+                            if (!onlyIfAbsent) {
+                                e.value = value;
+                                ++modCount;
+                            }
+                            break;
+                        }
+                        e = e.next;
+                    }
+                    else {
+                        if (node != null)
+                            node.setNext(first);
+                        else
+                            node = new HashEntry<K,V>(hash, key, value, first);
+                        int c = count + 1;
+                        if (c > threshold && tab.length < MAXIMUM_CAPACITY)
+                            rehash(node);
+                        else
+                            setEntryAt(tab, index, node);
+                        ++modCount;
+                        count = c;
+                        oldValue = null;
+                        break;
+                    }
+                }
+            } finally {
+                unlock();
+            }
+            return oldValue;
+        }
+
+        /**
+         * Doubles size of table and repacks entries, also adding the
+         * given node to new table
+         */
         @SuppressWarnings("unchecked")
-        static final <K,V> Segment<K,V>[] newArray(int i) {
-            return new Segment[i];
-        }
-
-        /**
-         * Sets table to new HashEntry array.
-         * Call only while holding lock or in constructor.
-         */
-        void setTable(HashEntry<K,V>[] newTable) {
-            threshold = (int)(newTable.length * loadFactor);
-            table = newTable;
-        }
-
-        /**
-         * Returns properly casted first entry of bin for given hash.
-         */
-        HashEntry<K,V> getFirst(int hash) {
-            HashEntry<K,V>[] tab = table;
-            return tab[hash & (tab.length - 1)];
-        }
-
-        /**
-         * Reads value field of an entry under lock. Called if value
-         * field ever appears to be null. This is possible only if a
-         * compiler happens to reorder a HashEntry initialization with
-         * its table assignment, which is legal under memory model
-         * but is not known to ever occur.
-         */
-        V readValueUnderLock(HashEntry<K,V> e) {
-            lock();
-            try {
-                return e.value;
-            } finally {
-                unlock();
-            }
-        }
-
-        /* Specialized implementations of map methods */
-
-        V get(Object key, int hash) {
-            if (count != 0) { // read-volatile
-                HashEntry<K,V> e = getFirst(hash);
-                while (e != null) {
-                    if (e.hash == hash && key.equals(e.key)) {
-                        V v = e.value;
-                        if (v != null)
-                            return v;
-                        return readValueUnderLock(e); // recheck
-                    }
-                    e = e.next;
-                }
-            }
-            return null;
-        }
-
-        boolean containsKey(Object key, int hash) {
-            if (count != 0) { // read-volatile
-                HashEntry<K,V> e = getFirst(hash);
-                while (e != null) {
-                    if (e.hash == hash && key.equals(e.key))
-                        return true;
-                    e = e.next;
-                }
-            }
-            return false;
-        }
-
-        boolean containsValue(Object value) {
-            if (count != 0) { // read-volatile
-                HashEntry<K,V>[] tab = table;
-                int len = tab.length;
-                for (int i = 0 ; i < len; i++) {
-                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
-                        V v = e.value;
-                        if (v == null) // recheck
-                            v = readValueUnderLock(e);
-                        if (value.equals(v))
-                            return true;
-                    }
-                }
-            }
-            return false;
-        }
-
-        boolean replace(K key, int hash, V oldValue, V newValue) {
-            lock();
-            try {
-                HashEntry<K,V> e = getFirst(hash);
-                while (e != null && (e.hash != hash || !key.equals(e.key)))
-                    e = e.next;
-
-                boolean replaced = false;
-                if (e != null && oldValue.equals(e.value)) {
-                    replaced = true;
-                    e.value = newValue;
-                }
-                return replaced;
-            } finally {
-                unlock();
-            }
-        }
-
-        V replace(K key, int hash, V newValue) {
-            lock();
-            try {
-                HashEntry<K,V> e = getFirst(hash);
-                while (e != null && (e.hash != hash || !key.equals(e.key)))
-                    e = e.next;
-
-                V oldValue = null;
-                if (e != null) {
-                    oldValue = e.value;
-                    e.value = newValue;
-                }
-                return oldValue;
-            } finally {
-                unlock();
-            }
-        }
-
-
-        V put(K key, int hash, V value, boolean onlyIfAbsent) {
-            lock();
-            try {
-                int c = count;
-                if (c++ > threshold) // ensure capacity
-                    rehash();
-                HashEntry<K,V>[] tab = table;
-                int index = hash & (tab.length - 1);
-                HashEntry<K,V> first = tab[index];
-                HashEntry<K,V> e = first;
-                while (e != null && (e.hash != hash || !key.equals(e.key)))
-                    e = e.next;
-
-                V oldValue;
-                if (e != null) {
-                    oldValue = e.value;
-                    if (!onlyIfAbsent)
-                        e.value = value;
-                }
-                else {
-                    oldValue = null;
-                    ++modCount;
-                    tab[index] = new HashEntry<K,V>(key, hash, first, value);
-                    count = c; // write-volatile
-                }
-                return oldValue;
-            } finally {
-                unlock();
-            }
-        }
-
-        void rehash() {
+        private void rehash(HashEntry<K,V> node) {
+            /*
+             * Reclassify nodes in each list to new table.  Because we
+             * are using power-of-two expansion, the elements from
+             * each bin must either stay at same index, or move with a
+             * power of two offset. We eliminate unnecessary node
+             * creation by catching cases where old nodes can be
+             * reused because their next fields won't change.
+             * Statistically, at the default threshold, only about
+             * one-sixth of them need cloning when a table
+             * doubles. The nodes they replace will be garbage
+             * collectable as soon as they are no longer referenced by
+             * any reader thread that may be in the midst of
+             * concurrently traversing table. Entry accesses use plain
+             * array indexing because they are followed by volatile
+             * table write.
+             */
             HashEntry<K,V>[] oldTable = table;
             int oldCapacity = oldTable.length;
-            if (oldCapacity >= MAXIMUM_CAPACITY)
-                return;
-
-            /*
-             * Reclassify nodes in each list to new Map.  Because we are
-             * using power-of-two expansion, the elements from each bin
-             * must either stay at same index, or move with a power of two
-             * offset. We eliminate unnecessary node creation by catching
-             * cases where old nodes can be reused because their next
-             * fields won't change. Statistically, at the default
-             * threshold, only about one-sixth of them need cloning when
-             * a table doubles. The nodes they replace will be garbage
-             * collectable as soon as they are no longer referenced by any
-             * reader thread that may be in the midst of traversing table
-             * right now.
-             */
-
-            HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1);
-            threshold = (int)(newTable.length * loadFactor);
-            int sizeMask = newTable.length - 1;
+            int newCapacity = oldCapacity << 1;
+            threshold = (int)(newCapacity * loadFactor);
+            HashEntry<K,V>[] newTable =
+                (HashEntry<K,V>[]) new HashEntry<?,?>[newCapacity];
+            int sizeMask = newCapacity - 1;
             for (int i = 0; i < oldCapacity ; i++) {
-                // We need to guarantee that any existing reads of old Map can
-                //  proceed. So we cannot yet null out each bin.
                 HashEntry<K,V> e = oldTable[i];
-
                 if (e != null) {
                     HashEntry<K,V> next = e.next;
                     int idx = e.hash & sizeMask;
-
-                    //  Single node on list
-                    if (next == null)
+                    if (next == null)   //  Single node on list
                         newTable[idx] = e;
-
-                    else {
-                        // Reuse trailing consecutive sequence at same slot
+                    else { // Reuse consecutive sequence at same slot
                         HashEntry<K,V> lastRun = e;
                         int lastIdx = idx;
                         for (HashEntry<K,V> last = next;
@@ -493,74 +423,263 @@
                             }
                         }
                         newTable[lastIdx] = lastRun;
-
-                        // Clone all remaining nodes
+                        // Clone remaining nodes
                         for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
-                            int k = p.hash & sizeMask;
+                            V v = p.value;
+                            int h = p.hash;
+                            int k = h & sizeMask;
                             HashEntry<K,V> n = newTable[k];
-                            newTable[k] = new HashEntry<K,V>(p.key, p.hash,
-                                                             n, p.value);
+                            newTable[k] = new HashEntry<K,V>(h, p.key, v, n);
                         }
                     }
                 }
             }
+            int nodeIndex = node.hash & sizeMask; // add the new node
+            node.setNext(newTable[nodeIndex]);
+            newTable[nodeIndex] = node;
             table = newTable;
         }
 
         /**
+         * Scans for a node containing given key while trying to
+         * acquire lock, creating and returning one if not found. Upon
+         * return, guarantees that lock is held. Unlike in most
+         * methods, calls to method equals are not screened: Since
+         * traversal speed doesn't matter, we might as well help warm
+         * up the associated code and accesses as well.
+         *
+         * @return a new node if key not found, else null
+         */
+        private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
+            HashEntry<K,V> first = entryForHash(this, hash);
+            HashEntry<K,V> e = first;
+            HashEntry<K,V> node = null;
+            int retries = -1; // negative while locating node
+            while (!tryLock()) {
+                HashEntry<K,V> f; // to recheck first below
+                if (retries < 0) {
+                    if (e == null) {
+                        if (node == null) // speculatively create node
+                            node = new HashEntry<K,V>(hash, key, value, null);
+                        retries = 0;
+                    }
+                    else if (key.equals(e.key))
+                        retries = 0;
+                    else
+                        e = e.next;
+                }
+                else if (++retries > MAX_SCAN_RETRIES) {
+                    lock();
+                    break;
+                }
+                else if ((retries & 1) == 0 &&
+                         (f = entryForHash(this, hash)) != first) {
+                    e = first = f; // re-traverse if entry changed
+                    retries = -1;
+                }
+            }
+            return node;
+        }
+
+        /**
+         * Scans for a node containing the given key while trying to
+         * acquire lock for a remove or replace operation. Upon
+         * return, guarantees that lock is held.  Note that we must
+         * lock even if the key is not found, to ensure sequential
+         * consistency of updates.
+         */
+        private void scanAndLock(Object key, int hash) {
+            // similar to but simpler than scanAndLockForPut
+            HashEntry<K,V> first = entryForHash(this, hash);
+            HashEntry<K,V> e = first;
+            int retries = -1;
+            while (!tryLock()) {
+                HashEntry<K,V> f;
+                if (retries < 0) {
+                    if (e == null || key.equals(e.key))
+                        retries = 0;
+                    else
+                        e = e.next;
+                }
+                else if (++retries > MAX_SCAN_RETRIES) {
+                    lock();
+                    break;
+                }
+                else if ((retries & 1) == 0 &&
+                         (f = entryForHash(this, hash)) != first) {
+                    e = first = f;
+                    retries = -1;
+                }
+            }
+        }
+
+        /**
          * Remove; match on key only if value null, else match both.
          */
-        V remove(Object key, int hash, Object value) {
-            lock();
+        final V remove(Object key, int hash, Object value) {
+            if (!tryLock())
+                scanAndLock(key, hash);
+            V oldValue = null;
             try {
-                int c = count - 1;
                 HashEntry<K,V>[] tab = table;
-                int index = hash & (tab.length - 1);
-                HashEntry<K,V> first = tab[index];
-                HashEntry<K,V> e = first;
-                while (e != null && (e.hash != hash || !key.equals(e.key)))
-                    e = e.next;
+                int index = (tab.length - 1) & hash;
+                HashEntry<K,V> e = entryAt(tab, index);
+                HashEntry<K,V> pred = null;
+                while (e != null) {
+                    K k;
+                    HashEntry<K,V> next = e.next;
+                    if ((k = e.key) == key ||
+                        (e.hash == hash && key.equals(k))) {
+                        V v = e.value;
+                        if (value == null || value == v || value.equals(v)) {
+                            if (pred == null)
+                                setEntryAt(tab, index, next);
+                            else
+                                pred.setNext(next);
+                            ++modCount;
+                            --count;
+                            oldValue = v;
+                        }
+                        break;
+                    }
+                    pred = e;
+                    e = next;
+                }
+            } finally {
+                unlock();
+            }
+            return oldValue;
+        }
 
-                V oldValue = null;
-                if (e != null) {
-                    V v = e.value;
-                    if (value == null || value.equals(v)) {
-                        oldValue = v;
-                        // All entries following removed node can stay
-                        // in list, but all preceding ones need to be
-                        // cloned.
-                        ++modCount;
-                        HashEntry<K,V> newFirst = e.next;
-                        for (HashEntry<K,V> p = first; p != e; p = p.next)
-                            newFirst = new HashEntry<K,V>(p.key, p.hash,
-                                                          newFirst, p.value);
-                        tab[index] = newFirst;
-                        count = c; // write-volatile
+        final boolean replace(K key, int hash, V oldValue, V newValue) {
+            if (!tryLock())
+                scanAndLock(key, hash);
+            boolean replaced = false;
+            try {
+                HashEntry<K,V> e;
+                for (e = entryForHash(this, hash); e != null; e = e.next) {
+                    K k;
+                    if ((k = e.key) == key ||
+                        (e.hash == hash && key.equals(k))) {
+                        if (oldValue.equals(e.value)) {
+                            e.value = newValue;
+                            ++modCount;
+                            replaced = true;
+                        }
+                        break;
                     }
                 }
-                return oldValue;
+            } finally {
+                unlock();
+            }
+            return replaced;
+        }
+
+        final V replace(K key, int hash, V value) {
+            if (!tryLock())
+                scanAndLock(key, hash);
+            V oldValue = null;
+            try {
+                HashEntry<K,V> e;
+                for (e = entryForHash(this, hash); e != null; e = e.next) {
+                    K k;
+                    if ((k = e.key) == key ||
+                        (e.hash == hash && key.equals(k))) {
+                        oldValue = e.value;
+                        e.value = value;
+                        ++modCount;
+                        break;
+                    }
+                }
+            } finally {
+                unlock();
+            }
+            return oldValue;
+        }
+
+        final void clear() {
+            lock();
+            try {
+                HashEntry<K,V>[] tab = table;
+                for (int i = 0; i < tab.length ; i++)
+                    setEntryAt(tab, i, null);
+                ++modCount;
+                count = 0;
             } finally {
                 unlock();
             }
         }
+    }
 
-        void clear() {
-            if (count != 0) {
-                lock();
-                try {
-                    HashEntry<K,V>[] tab = table;
-                    for (int i = 0; i < tab.length ; i++)
-                        tab[i] = null;
-                    ++modCount;
-                    count = 0; // write-volatile
-                } finally {
-                    unlock();
+    // Accessing segments
+
+    /**
+     * Gets the jth element of given segment array (if nonnull) with
+     * volatile element access semantics via Unsafe. (The null check
+     * can trigger harmlessly only during deserialization.) Note:
+     * because each element of segments array is set only once (using
+     * fully ordered writes), some performance-sensitive methods rely
+     * on this method only as a recheck upon null reads.
+     */
+    @SuppressWarnings("unchecked")
+    static final <K,V> Segment<K,V> segmentAt(Segment<K,V>[] ss, int j) {
+        long u = (j << SSHIFT) + SBASE;
+        return ss == null ? null :
+            (Segment<K,V>) UNSAFE.getObjectVolatile(ss, u);
+    }
+
+    /**
+     * Returns the segment for the given index, creating it and
+     * recording in segment table (via CAS) if not already present.
+     *
+     * @param k the index
+     * @return the segment
+     */
+    @SuppressWarnings("unchecked")
+    private Segment<K,V> ensureSegment(int k) {
+        final Segment<K,V>[] ss = this.segments;
+        long u = (k << SSHIFT) + SBASE; // raw offset
+        Segment<K,V> seg;
+        if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
+            Segment<K,V> proto = ss[0]; // use segment 0 as prototype
+            int cap = proto.table.length;
+            float lf = proto.loadFactor;
+            int threshold = (int)(cap * lf);
+            HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry<?,?>[cap];
+            if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
+                == null) { // recheck
+                Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
+                while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
+                       == null) {
+                    if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
+                        break;
                 }
             }
         }
+        return seg;
     }
 
+    // Hash-based segment and entry accesses
 
+    /**
+     * Gets the segment for the given hash code.
+     */
+    @SuppressWarnings("unchecked")
+    private Segment<K,V> segmentForHash(int h) {
+        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
+        return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u);
+    }
+
+    /**
+     * Gets the table entry for the given segment and hash code.
+     */
+    @SuppressWarnings("unchecked")
+    static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) {
+        HashEntry<K,V>[] tab;
+        return (seg == null || (tab = seg.table) == null) ? null :
+            (HashEntry<K,V>) UNSAFE.getObjectVolatile
+            (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
+    }
 
     /* ---------------- Public operations -------------- */
 
@@ -580,14 +699,13 @@
      * negative or the load factor or concurrencyLevel are
      * nonpositive.
      */
+    @SuppressWarnings("unchecked")
     public ConcurrentHashMap(int initialCapacity,
                              float loadFactor, int concurrencyLevel) {
         if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
             throw new IllegalArgumentException();
-
         if (concurrencyLevel > MAX_SEGMENTS)
             concurrencyLevel = MAX_SEGMENTS;
-
         // Find power-of-two sizes best matching arguments
         int sshift = 0;
         int ssize = 1;
@@ -595,21 +713,23 @@
             ++sshift;
             ssize <<= 1;
         }
-        segmentShift = 32 - sshift;
-        segmentMask = ssize - 1;
-        this.segments = Segment.newArray(ssize);
-
+        this.segmentShift = 32 - sshift;
+        this.segmentMask = ssize - 1;
         if (initialCapacity > MAXIMUM_CAPACITY)
             initialCapacity = MAXIMUM_CAPACITY;
         int c = initialCapacity / ssize;
         if (c * ssize < initialCapacity)
             ++c;
-        int cap = 1;
+        int cap = MIN_SEGMENT_TABLE_CAPACITY;
         while (cap < c)
             cap <<= 1;
-
-        for (int i = 0; i < this.segments.length; ++i)
-            this.segments[i] = new Segment<K,V>(cap, loadFactor);
+        // create segments and segments[0]
+        Segment<K,V> s0 =
+            new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
+                             (HashEntry<K,V>[])new HashEntry<?,?>[cap]);
+        Segment<K,V>[] ss = (Segment<K,V>[])new Segment<?,?>[ssize];
+        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
+        this.segments = ss;
     }
 
     /**
@@ -672,34 +792,37 @@
      * @return <tt>true</tt> if this map contains no key-value mappings
      */
     public boolean isEmpty() {
-        final Segment<K,V>[] segments = this.segments;
         /*
-         * We keep track of per-segment modCounts to avoid ABA
-         * problems in which an element in one segment was added and
-         * in another removed during traversal, in which case the
-         * table was never actually empty at any point. Note the
-         * similar use of modCounts in the size() and containsValue()
-         * methods, which are the only other methods also susceptible
-         * to ABA problems.
+         * Sum per-segment modCounts to avoid mis-reporting when
+         * elements are concurrently added and removed in one segment
+         * while checking another, in which case the table was never
+         * actually empty at any point. (The sum ensures accuracy up
+         * through at least 1<<31 per-segment modifications before
+         * recheck.)  Methods size() and containsValue() use similar
+         * constructions for stability checks.
          */
-        int[] mc = new int[segments.length];
-        int mcsum = 0;
-        for (int i = 0; i < segments.length; ++i) {
-            if (segments[i].count != 0)
-                return false;
-            else
-                mcsum += mc[i] = segments[i].modCount;
-        }
-        // If mcsum happens to be zero, then we know we got a snapshot
-        // before any modifications at all were made.  This is
-        // probably common enough to bother tracking.
-        if (mcsum != 0) {
-            for (int i = 0; i < segments.length; ++i) {
-                if (segments[i].count != 0 ||
-                    mc[i] != segments[i].modCount)
+        long sum = 0L;
+        final Segment<K,V>[] segments = this.segments;
+        for (int j = 0; j < segments.length; ++j) {
+            Segment<K,V> seg = segmentAt(segments, j);
+            if (seg != null) {
+                if (seg.count != 0)
                     return false;
+                sum += seg.modCount;
             }
         }
+        if (sum != 0L) { // recheck unless no modifications
+            for (int j = 0; j < segments.length; ++j) {
+                Segment<K,V> seg = segmentAt(segments, j);
+                if (seg != null) {
+                    if (seg.count != 0)
+                        return false;
+                    sum -= seg.modCount;
+                }
+            }
+            if (sum != 0L)
+                return false;
+        }
         return true;
     }
 
@@ -711,45 +834,36 @@
      * @return the number of key-value mappings in this map
      */
     public int size() {
-        final Segment<K,V>[] segments = this.segments;
-        long sum = 0;
-        long check = 0;
-        int[] mc = new int[segments.length];
         // Try a few times to get accurate count. On failure due to
         // continuous async changes in table, resort to locking.
-        for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
-            check = 0;
-            sum = 0;
-            int mcsum = 0;
-            for (int i = 0; i < segments.length; ++i) {
-                sum += segments[i].count;
-                mcsum += mc[i] = segments[i].modCount;
-            }
-            if (mcsum != 0) {
-                for (int i = 0; i < segments.length; ++i) {
-                    check += segments[i].count;
-                    if (mc[i] != segments[i].modCount) {
-                        check = -1; // force retry
-                        break;
-                    }
+        final Segment<K,V>[] segments = this.segments;
+        final int segmentCount = segments.length;
+
+        long previousSum = 0L;
+        for (int retries = -1; retries < RETRIES_BEFORE_LOCK; retries++) {
+            long sum = 0L;    // sum of modCounts
+            long size = 0L;
+            for (int i = 0; i < segmentCount; i++) {
+                Segment<K,V> segment = segmentAt(segments, i);
+                if (segment != null) {
+                    sum += segment.modCount;
+                    size += segment.count;
                 }
             }
-            if (check == sum)
-                break;
+            if (sum == previousSum)
+                return ((size >>> 31) == 0) ? (int) size : Integer.MAX_VALUE;
+            previousSum = sum;
         }
-        if (check != sum) { // Resort to locking all segments
-            sum = 0;
-            for (int i = 0; i < segments.length; ++i)
-                segments[i].lock();
-            for (int i = 0; i < segments.length; ++i)
-                sum += segments[i].count;
-            for (int i = 0; i < segments.length; ++i)
-                segments[i].unlock();
+
+        long size = 0L;
+        for (int i = 0; i < segmentCount; i++) {
+            Segment<K,V> segment = ensureSegment(i);
+            segment.lock();
+            size += segment.count;
         }
-        if (sum > Integer.MAX_VALUE)
-            return Integer.MAX_VALUE;
-        else
-            return (int)sum;
+        for (int i = 0; i < segmentCount; i++)
+            segments[i].unlock();
+        return ((size >>> 31) == 0) ? (int) size : Integer.MAX_VALUE;
     }
 
     /**
@@ -764,8 +878,21 @@
      * @throws NullPointerException if the specified key is null
      */
     public V get(Object key) {
-        int hash = hash(key.hashCode());
-        return segmentFor(hash).get(key, hash);
+        Segment<K,V> s; // manually integrate access methods to reduce overhead
+        HashEntry<K,V>[] tab;
+        int h = hash(key.hashCode());
+        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
+        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
+            (tab = s.table) != null) {
+            for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
+                     (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
+                 e != null; e = e.next) {
+                K k;
+                if ((k = e.key) == key || (e.hash == h && key.equals(k)))
+                    return e.value;
+            }
+        }
+        return null;
     }
 
     /**
@@ -777,9 +904,23 @@
      *         <tt>equals</tt> method; <tt>false</tt> otherwise.
      * @throws NullPointerException if the specified key is null
      */
+    @SuppressWarnings("unchecked")
     public boolean containsKey(Object key) {
-        int hash = hash(key.hashCode());
-        return segmentFor(hash).containsKey(key, hash);
+        Segment<K,V> s; // same as get() except no need for volatile value read
+        HashEntry<K,V>[] tab;
+        int h = hash(key.hashCode());
+        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
+        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
+            (tab = s.table) != null) {
+            for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
+                     (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
+                 e != null; e = e.next) {
+                K k;
+                if ((k = e.key) == key || (e.hash == h && key.equals(k)))
+                    return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -794,53 +935,47 @@
      * @throws NullPointerException if the specified value is null
      */
     public boolean containsValue(Object value) {
+        // Same idea as size()
         if (value == null)
             throw new NullPointerException();
-
-        // See explanation of modCount use above
-
         final Segment<K,V>[] segments = this.segments;
-        int[] mc = new int[segments.length];
-
-        // Try a few times without locking
-        for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
-            int sum = 0;
-            int mcsum = 0;
-            for (int i = 0; i < segments.length; ++i) {
-                int c = segments[i].count;
-                mcsum += mc[i] = segments[i].modCount;
-                if (segments[i].containsValue(value))
-                    return true;
-            }
-            boolean cleanSweep = true;
-            if (mcsum != 0) {
-                for (int i = 0; i < segments.length; ++i) {
-                    int c = segments[i].count;
-                    if (mc[i] != segments[i].modCount) {
-                        cleanSweep = false;
-                        break;
+        long previousSum = 0L;
+        int lockCount = 0;
+        try {
+            for (int retries = -1; ; retries++) {
+                long sum = 0L;    // sum of modCounts
+                for (int j = 0; j < segments.length; j++) {
+                    Segment<K,V> segment;
+                    if (retries == RETRIES_BEFORE_LOCK) {
+                        segment = ensureSegment(j);
+                        segment.lock();
+                        lockCount++;
+                    } else {
+                        segment = segmentAt(segments, j);
+                        if (segment == null)
+                            continue;
+                    }
+                    HashEntry<K,V>[] tab = segment.table;
+                    if (tab != null) {
+                        for (int i = 0 ; i < tab.length; i++) {
+                            HashEntry<K,V> e;
+                            for (e = entryAt(tab, i); e != null; e = e.next) {
+                                V v = e.value;
+                                if (v != null && value.equals(v))
+                                    return true;
+                            }
+                        }
+                        sum += segment.modCount;
                     }
                 }
-            }
-            if (cleanSweep)
-                return false;
-        }
-        // Resort to locking all segments
-        for (int i = 0; i < segments.length; ++i)
-            segments[i].lock();
-        boolean found = false;
-        try {
-            for (int i = 0; i < segments.length; ++i) {
-                if (segments[i].containsValue(value)) {
-                    found = true;
-                    break;
-                }
+                if ((retries >= 0 && sum == previousSum) || lockCount > 0)
+                    return false;
+                previousSum = sum;
             }
         } finally {
-            for (int i = 0; i < segments.length; ++i)
-                segments[i].unlock();
+            for (int j = 0; j < lockCount; j++)
+                segments[j].unlock();
         }
-        return found;
     }
 
     /**
@@ -850,7 +985,7 @@
      * full compatibility with class {@link java.util.Hashtable},
      * which supported this method prior to introduction of the
      * Java Collections framework.
-
+     *
      * @param  value a value to search for
      * @return <tt>true</tt> if and only if some key maps to the
      *         <tt>value</tt> argument in this table as
@@ -875,11 +1010,17 @@
      *         <tt>null</tt> if there was no mapping for <tt>key</tt>
      * @throws NullPointerException if the specified key or value is null
      */
+    @SuppressWarnings("unchecked")
     public V put(K key, V value) {
+        Segment<K,V> s;
         if (value == null)
             throw new NullPointerException();
         int hash = hash(key.hashCode());
-        return segmentFor(hash).put(key, hash, value, false);
+        int j = (hash >>> segmentShift) & segmentMask;
+        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
+             (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
+            s = ensureSegment(j);
+        return s.put(key, hash, value, false);
     }
 
     /**
@@ -889,11 +1030,17 @@
      *         or <tt>null</tt> if there was no mapping for the key
      * @throws NullPointerException if the specified key or value is null
      */
+    @SuppressWarnings("unchecked")
     public V putIfAbsent(K key, V value) {
+        Segment<K,V> s;
         if (value == null)
             throw new NullPointerException();
         int hash = hash(key.hashCode());
-        return segmentFor(hash).put(key, hash, value, true);
+        int j = (hash >>> segmentShift) & segmentMask;
+        if ((s = (Segment<K,V>)UNSAFE.getObject
+             (segments, (j << SSHIFT) + SBASE)) == null)
+            s = ensureSegment(j);
+        return s.put(key, hash, value, true);
     }
 
     /**
@@ -919,7 +1066,8 @@
      */
     public V remove(Object key) {
         int hash = hash(key.hashCode());
-        return segmentFor(hash).remove(key, hash, null);
+        Segment<K,V> s = segmentForHash(hash);
+        return s == null ? null : s.remove(key, hash, null);
     }
 
     /**
@@ -929,9 +1077,9 @@
      */
     public boolean remove(Object key, Object value) {
         int hash = hash(key.hashCode());
-        if (value == null)
-            return false;
-        return segmentFor(hash).remove(key, hash, value) != null;
+        Segment<K,V> s;
+        return value != null && (s = segmentForHash(hash)) != null &&
+            s.remove(key, hash, value) != null;
     }
 
     /**
@@ -940,10 +1088,11 @@
      * @throws NullPointerException if any of the arguments are null
      */
     public boolean replace(K key, V oldValue, V newValue) {
+        int hash = hash(key.hashCode());
         if (oldValue == null || newValue == null)
             throw new NullPointerException();
-        int hash = hash(key.hashCode());
-        return segmentFor(hash).replace(key, hash, oldValue, newValue);
+        Segment<K,V> s = segmentForHash(hash);
+        return s != null && s.replace(key, hash, oldValue, newValue);
     }
 
     /**
@@ -954,18 +1103,23 @@
      * @throws NullPointerException if the specified key or value is null
      */
     public V replace(K key, V value) {
+        int hash = hash(key.hashCode());
         if (value == null)
             throw new NullPointerException();
-        int hash = hash(key.hashCode());
-        return segmentFor(hash).replace(key, hash, value);
+        Segment<K,V> s = segmentForHash(hash);
+        return s == null ? null : s.replace(key, hash, value);
     }
 
     /**
      * Removes all of the mappings from this map.
      */
     public void clear() {
-        for (int i = 0; i < segments.length; ++i)
-            segments[i].clear();
+        final Segment<K,V>[] segments = this.segments;
+        for (int j = 0; j < segments.length; ++j) {
+            Segment<K,V> s = segmentAt(segments, j);
+            if (s != null)
+                s.clear();
+        }
     }
 
     /**
@@ -1066,42 +1220,41 @@
             advance();
         }
 
-        public boolean hasMoreElements() { return hasNext(); }
-
+        /**
+         * Sets nextEntry to first node of next non-empty table
+         * (in backwards order, to simplify checks).
+         */
         final void advance() {
-            if (nextEntry != null && (nextEntry = nextEntry.next) != null)
-                return;
-
-            while (nextTableIndex >= 0) {
-                if ( (nextEntry = currentTable[nextTableIndex--]) != null)
-                    return;
-            }
-
-            while (nextSegmentIndex >= 0) {
-                Segment<K,V> seg = segments[nextSegmentIndex--];
-                if (seg.count != 0) {
-                    currentTable = seg.table;
-                    for (int j = currentTable.length - 1; j >= 0; --j) {
-                        if ( (nextEntry = currentTable[j]) != null) {
-                            nextTableIndex = j - 1;
-                            return;
-                        }
-                    }
+            for (;;) {
+                if (nextTableIndex >= 0) {
+                    if ((nextEntry = entryAt(currentTable,
+                                             nextTableIndex--)) != null)
+                        break;
                 }
+                else if (nextSegmentIndex >= 0) {
+                    Segment<K,V> seg = segmentAt(segments, nextSegmentIndex--);
+                    if (seg != null && (currentTable = seg.table) != null)
+                        nextTableIndex = currentTable.length - 1;
+                }
+                else
+                    break;
             }
         }
 
-        public boolean hasNext() { return nextEntry != null; }
-
-        HashEntry<K,V> nextEntry() {
-            if (nextEntry == null)
+        final HashEntry<K,V> nextEntry() {
+            HashEntry<K,V> e = nextEntry;
+            if (e == null)
                 throw new NoSuchElementException();
-            lastReturned = nextEntry;
-            advance();
-            return lastReturned;
+            lastReturned = e; // cannot assign until after null check
+            if ((nextEntry = e.next) == null)
+                advance();
+            return e;
         }
 
-        public void remove() {
+        public final boolean hasNext() { return nextEntry != null; }
+        public final boolean hasMoreElements() { return nextEntry != null; }
+
+        public final void remove() {
             if (lastReturned == null)
                 throw new IllegalStateException();
             ConcurrentHashMap.this.remove(lastReturned.key);
@@ -1113,16 +1266,16 @@
         extends HashIterator
         implements Iterator<K>, Enumeration<K>
     {
-        public K next()        { return super.nextEntry().key; }
-        public K nextElement() { return super.nextEntry().key; }
+        public final K next()        { return super.nextEntry().key; }
+        public final K nextElement() { return super.nextEntry().key; }
     }
 
     final class ValueIterator
         extends HashIterator
         implements Iterator<V>, Enumeration<V>
     {
-        public V next()        { return super.nextEntry().value; }
-        public V nextElement() { return super.nextEntry().value; }
+        public final V next()        { return super.nextEntry().value; }
+        public final V nextElement() { return super.nextEntry().value; }
     }
 
     /**
@@ -1137,7 +1290,7 @@
         }
 
         /**
-         * Set our entry's value and write through to the map. The
+         * Sets our entry's value and writes through to the map. The
          * value to return is somewhat arbitrary here. Since a
          * WriteThroughEntry does not necessarily track asynchronous
          * changes, the most recent "previous" value could be
@@ -1233,24 +1386,30 @@
     /* ---------------- Serialization Support -------------- */
 
     /**
-     * Save the state of the <tt>ConcurrentHashMap</tt> instance to a
-     * stream (i.e., serialize it).
+     * Saves the state of the <tt>ConcurrentHashMap</tt> instance to a
+     * stream (i.e., serializes it).
      * @param s the stream
      * @serialData
      * the key (Object) and value (Object)
      * for each key-value mapping, followed by a null pair.
      * The key-value mappings are emitted in no particular order.
      */
-    private void writeObject(java.io.ObjectOutputStream s) throws IOException {
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws java.io.IOException {
+        // force all segments for serialization compatibility
+        for (int k = 0; k < segments.length; ++k)
+            ensureSegment(k);
         s.defaultWriteObject();
 
+        final Segment<K,V>[] segments = this.segments;
         for (int k = 0; k < segments.length; ++k) {
-            Segment<K,V> seg = segments[k];
+            Segment<K,V> seg = segmentAt(segments, k);
             seg.lock();
             try {
                 HashEntry<K,V>[] tab = seg.table;
                 for (int i = 0; i < tab.length; ++i) {
-                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
+                    HashEntry<K,V> e;
+                    for (e = entryAt(tab, i); e != null; e = e.next) {
                         s.writeObject(e.key);
                         s.writeObject(e.value);
                     }
@@ -1264,17 +1423,24 @@
     }
 
     /**
-     * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
-     * stream (i.e., deserialize it).
+     * Reconstitutes the <tt>ConcurrentHashMap</tt> instance from a
+     * stream (i.e., deserializes it).
      * @param s the stream
      */
+    @SuppressWarnings("unchecked")
     private void readObject(java.io.ObjectInputStream s)
-        throws IOException, ClassNotFoundException {
+            throws java.io.IOException, ClassNotFoundException {
         s.defaultReadObject();
 
-        // Initialize each segment to be minimally sized, and let grow.
-        for (int i = 0; i < segments.length; ++i) {
-            segments[i].setTable(new HashEntry[1]);
+        // Re-initialize segments to be minimally sized, and let grow.
+        int cap = MIN_SEGMENT_TABLE_CAPACITY;
+        final Segment<K,V>[] segments = this.segments;
+        for (int k = 0; k < segments.length; ++k) {
+            Segment<K,V> seg = segments[k];
+            if (seg != null) {
+                seg.threshold = (int)(cap * seg.loadFactor);
+                seg.table = (HashEntry<K,V>[]) new HashEntry<?,?>[cap];
+            }
         }
 
         // Read the keys and values, and put the mappings in the table
@@ -1286,4 +1452,31 @@
             put(key, value);
         }
     }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long SBASE;
+    private static final int SSHIFT;
+    private static final long TBASE;
+    private static final int TSHIFT;
+
+    static {
+        int ss, ts;
+        try {
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> tc = HashEntry[].class;
+            Class<?> sc = Segment[].class;
+            TBASE = UNSAFE.arrayBaseOffset(tc);
+            SBASE = UNSAFE.arrayBaseOffset(sc);
+            ts = UNSAFE.arrayIndexScale(tc);
+            ss = UNSAFE.arrayIndexScale(sc);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+        if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
+            throw new Error("data type scale not a power of two");
+        SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
+        TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
+    }
+
 }
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
index 72c2e08..30adb36 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea and Martin Buchholz with assistance from members of
  * JCP JSR-166 Expert Group and released to the public domain, as explained
- * at http://creativecommons.org/licenses/publicdomain
+ * at http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -34,10 +34,17 @@
  * ConcurrentModificationException}, and may proceed concurrently with
  * other operations.
  *
- * <p>Beware that, unlike in most collections, the {@code size}
- * method is <em>NOT</em> a constant-time operation. Because of the
+ * <p>Beware that, unlike in most collections, the {@code size} method
+ * is <em>NOT</em> a constant-time operation. Because of the
  * asynchronous nature of these deques, determining the current number
- * of elements requires a traversal of the elements.
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
  *
  * <p>This class and its iterator implement all of the <em>optional</em>
  * methods of the {@link Deque} and {@link Iterator} interfaces.
@@ -245,13 +252,6 @@
 
     private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
 
-    static {
-        PREV_TERMINATOR = new Node<Object>(null);
-        PREV_TERMINATOR.next = PREV_TERMINATOR;
-        NEXT_TERMINATOR = new Node<Object>(null);
-        NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
-    }
-
     @SuppressWarnings("unchecked")
     Node<E> prevTerminator() {
         return (Node<E>) PREV_TERMINATOR;
@@ -267,6 +267,9 @@
         volatile E item;
         volatile Node<E> next;
 
+        Node() {  // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
+        }
+
         /**
          * Constructs a new node.  Uses relaxed write because item can
          * only be seen after publication via casNext or casPrev.
@@ -297,14 +300,25 @@
 
         // Unsafe mechanics
 
-        private static final sun.misc.Unsafe UNSAFE =
-            sun.misc.Unsafe.getUnsafe();
-        private static final long prevOffset =
-            objectFieldOffset(UNSAFE, "prev", Node.class);
-        private static final long itemOffset =
-            objectFieldOffset(UNSAFE, "item", Node.class);
-        private static final long nextOffset =
-            objectFieldOffset(UNSAFE, "next", Node.class);
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long prevOffset;
+        private static final long itemOffset;
+        private static final long nextOffset;
+
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class<?> k = Node.class;
+                prevOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("prev"));
+                itemOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("item"));
+                nextOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("next"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /**
@@ -1209,8 +1223,7 @@
      * The following code can be used to dump the deque into a newly
      * allocated array of {@code String}:
      *
-     * <pre>
-     *     String[] y = x.toArray(new String[0]);</pre>
+     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
      *
      * Note that {@code toArray(new Object[0])} is identical in function to
      * {@code toArray()}.
@@ -1395,14 +1408,6 @@
         initHeadTail(h, t);
     }
 
-    // Unsafe mechanics
-
-    private static final sun.misc.Unsafe UNSAFE =
-        sun.misc.Unsafe.getUnsafe();
-    private static final long headOffset =
-        objectFieldOffset(UNSAFE, "head", ConcurrentLinkedDeque.class);
-    private static final long tailOffset =
-        objectFieldOffset(UNSAFE, "tail", ConcurrentLinkedDeque.class);
 
     private boolean casHead(Node<E> cmp, Node<E> val) {
         return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
@@ -1412,15 +1417,25 @@
         return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
     }
 
-    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
-                                  String field, Class<?> klazz) {
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long headOffset;
+    private static final long tailOffset;
+    static {
+        PREV_TERMINATOR = new Node<Object>();
+        PREV_TERMINATOR.next = PREV_TERMINATOR;
+        NEXT_TERMINATOR = new Node<Object>();
+        NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = ConcurrentLinkedDeque.class;
+            headOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("head"));
+            tailOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("tail"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
 }
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
index 3ed0a7c..a0a26fd 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea and Martin Buchholz with assistance from members of
  * JCP JSR-166 Expert Group and released to the public domain, as explained
- * at http://creativecommons.org/licenses/publicdomain
+ * at http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -47,7 +47,14 @@
  * <p>Beware that, unlike in most collections, the {@code size} method
  * is <em>NOT</em> a constant-time operation. Because of the
  * asynchronous nature of these queues, determining the current number
- * of elements requires a traversal of the elements.
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
  *
  * <p>This class and its iterator implement all of the <em>optional</em>
  * methods of the {@link Queue} and {@link Iterator} interfaces.
@@ -165,12 +172,22 @@
 
         // Unsafe mechanics
 
-        private static final sun.misc.Unsafe UNSAFE =
-            sun.misc.Unsafe.getUnsafe();
-        private static final long nextOffset =
-            objectFieldOffset(UNSAFE, "next", Node.class);
-        private static final long itemOffset =
-            objectFieldOffset(UNSAFE, "item", Node.class);
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long itemOffset;
+        private static final long nextOffset;
+
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class<?> k = Node.class;
+                itemOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("item"));
+                nextOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("next"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /**
@@ -563,8 +580,7 @@
      * The following code can be used to dump the queue into a newly
      * allocated array of {@code String}:
      *
-     * <pre>
-     *     String[] y = x.toArray(new String[0]);</pre>
+     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
      *
      * Note that {@code toArray(new Object[0])} is identical in function to
      * {@code toArray()}.
@@ -761,14 +777,6 @@
             throw new NullPointerException();
     }
 
-    // Unsafe mechanics
-
-    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-    private static final long headOffset =
-        objectFieldOffset(UNSAFE, "head", ConcurrentLinkedQueue.class);
-    private static final long tailOffset =
-        objectFieldOffset(UNSAFE, "tail", ConcurrentLinkedQueue.class);
-
     private boolean casTail(Node<E> cmp, Node<E> val) {
         return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
     }
@@ -777,15 +785,21 @@
         return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
     }
 
-    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
-                                  String field, Class<?> klazz) {
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long headOffset;
+    private static final long tailOffset;
+    static {
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = ConcurrentLinkedQueue.class;
+            headOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("head"));
+            tailOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("tail"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
 }
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentMap.java
index 2daebc5..3405acf 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentMap.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -32,11 +32,12 @@
      * If the specified key is not already associated
      * with a value, associate it with the given value.
      * This is equivalent to
-     * <pre>
-     *   if (!map.containsKey(key))
-     *       return map.put(key, value);
-     *   else
-     *       return map.get(key);</pre>
+     *  <pre> {@code
+     * if (!map.containsKey(key))
+     *   return map.put(key, value);
+     * else
+     *   return map.get(key);}</pre>
+     *
      * except that the action is performed atomically.
      *
      * @param key key with which the specified value is to be associated
@@ -61,11 +62,13 @@
     /**
      * Removes the entry for a key only if currently mapped to a given value.
      * This is equivalent to
-     * <pre>
-     *   if (map.containsKey(key) &amp;&amp; map.get(key).equals(value)) {
-     *       map.remove(key);
-     *       return true;
-     *   } else return false;</pre>
+     *  <pre> {@code
+     * if (map.containsKey(key) && map.get(key).equals(value)) {
+     *   map.remove(key);
+     *   return true;
+     * } else
+     *   return false;}</pre>
+     *
      * except that the action is performed atomically.
      *
      * @param key key with which the specified value is associated
@@ -74,20 +77,24 @@
      * @throws UnsupportedOperationException if the <tt>remove</tt> operation
      *         is not supported by this map
      * @throws ClassCastException if the key or value is of an inappropriate
-     *         type for this map (optional)
+     *         type for this map
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified key or value is null,
-     *         and this map does not permit null keys or values (optional)
+     *         and this map does not permit null keys or values
+     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
      */
     boolean remove(Object key, Object value);
 
     /**
      * Replaces the entry for a key only if currently mapped to a given value.
      * This is equivalent to
-     * <pre>
-     *   if (map.containsKey(key) &amp;&amp; map.get(key).equals(oldValue)) {
-     *       map.put(key, newValue);
-     *       return true;
-     *   } else return false;</pre>
+     *  <pre> {@code
+     * if (map.containsKey(key) && map.get(key).equals(oldValue)) {
+     *   map.put(key, newValue);
+     *   return true;
+     * } else
+     *   return false;}</pre>
+     *
      * except that the action is performed atomically.
      *
      * @param key key with which the specified value is associated
@@ -108,10 +115,12 @@
     /**
      * Replaces the entry for a key only if currently mapped to some value.
      * This is equivalent to
-     * <pre>
-     *   if (map.containsKey(key)) {
-     *       return map.put(key, value);
-     *   } else return null;</pre>
+     *  <pre> {@code
+     * if (map.containsKey(key)) {
+     *   return map.put(key, value);
+     * } else
+     *   return null;}</pre>
+     *
      * except that the action is performed atomically.
      *
      * @param key key with which the specified value is associated
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
index 7d86afb..ea99886 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentNavigableMap.java
@@ -1,20 +1,20 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
 import java.util.*;
 
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
 /**
  * A {@link ConcurrentMap} supporting {@link NavigableMap} operations,
  * and recursively so for its navigable sub-maps.
  *
- * <p>This interface is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
- * Java Collections Framework</a>.
- *
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
index fbd1083..d0d6f14 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListMap.java
@@ -1,12 +1,15 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
 import java.util.*;
-import java.util.concurrent.atomic.*;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * A scalable concurrent {@link ConcurrentNavigableMap} implementation.
@@ -15,8 +18,8 @@
  * creation time, depending on which constructor is used.
  *
  * <p>This class implements a concurrent variant of <a
- * href="http://www.cs.umd.edu/~pugh/">SkipLists</a> providing
- * expected average <i>log(n)</i> time cost for the
+ * href="http://en.wikipedia.org/wiki/Skip_list" target="_top">SkipLists</a>
+ * providing expected average <i>log(n)</i> time cost for the
  * <tt>containsKey</tt>, <tt>get</tt>, <tt>put</tt> and
  * <tt>remove</tt> operations and their variants.  Insertion, removal,
  * update, and access operations safely execute concurrently by
@@ -37,12 +40,13 @@
  * <p>Beware that, unlike in most collections, the <tt>size</tt>
  * method is <em>not</em> a constant-time operation. Because of the
  * asynchronous nature of these maps, determining the current number
- * of elements requires a traversal of the elements.  Additionally,
- * the bulk operations <tt>putAll</tt>, <tt>equals</tt>, and
- * <tt>clear</tt> are <em>not</em> guaranteed to be performed
- * atomically. For example, an iterator operating concurrently with a
- * <tt>putAll</tt> operation might view only some of the added
- * elements.
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations <tt>putAll</tt>, <tt>equals</tt>,
+ * <tt>toArray</tt>, <tt>containsValue</tt>, and <tt>clear</tt> are
+ * <em>not</em> guaranteed to be performed atomically. For example, an
+ * iterator operating concurrently with a <tt>putAll</tt> operation
+ * might view only some of the added elements.
  *
  * <p>This class and its views and iterators implement all of the
  * <em>optional</em> methods of the {@link Map} and {@link Iterator}
@@ -51,10 +55,6 @@
  * null return values cannot be reliably distinguished from the absence of
  * elements.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
- * Java Collections Framework</a>.
- *
  * @author Doug Lea
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
@@ -322,11 +322,11 @@
     private transient int randomSeed;
 
     /** Lazily initialized key set */
-    private transient KeySet keySet;
+    private transient KeySet<K> keySet;
     /** Lazily initialized entry set */
-    private transient EntrySet entrySet;
+    private transient EntrySet<K,V> entrySet;
     /** Lazily initialized values collection */
-    private transient Values values;
+    private transient Values<V> values;
     /** Lazily initialized descending key set */
     private transient ConcurrentNavigableMap<K,V> descendingMap;
 
@@ -478,13 +478,24 @@
             return new AbstractMap.SimpleImmutableEntry<K,V>(key, v);
         }
 
-        // Unsafe mechanics
-        private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-        private static final long valueOffset =
-            objectFieldOffset(UNSAFE, "value", Node.class);
-        private static final long nextOffset =
-            objectFieldOffset(UNSAFE, "next", Node.class);
+        // UNSAFE mechanics
 
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long valueOffset;
+        private static final long nextOffset;
+
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class<?> k = Node.class;
+                valueOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("value"));
+                nextOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("next"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /* ---------------- Indexing -------------- */
@@ -551,10 +562,18 @@
         }
 
         // Unsafe mechanics
-        private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-        private static final long rightOffset =
-            objectFieldOffset(UNSAFE, "right", Index.class);
-
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long rightOffset;
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class<?> k = Index.class;
+                rightOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("right"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /* ---------------- Head nodes -------------- */
@@ -884,7 +903,7 @@
              * direction.
              */
             level = max + 1;
-            Index<K,V>[] idxs = (Index<K,V>[])new Index[level+1];
+            Index<K,V>[] idxs = (Index<K,V>[])new Index<?,?>[level+1];
             Index<K,V> idx = null;
             for (int i = 1; i <= level; ++i)
                 idxs[i] = idx = new Index<K,V>(z, idx, null);
@@ -1387,16 +1406,16 @@
      * @return a shallow copy of this map
      */
     public ConcurrentSkipListMap<K,V> clone() {
-        ConcurrentSkipListMap<K,V> clone = null;
         try {
-            clone = (ConcurrentSkipListMap<K,V>) super.clone();
+            @SuppressWarnings("unchecked")
+            ConcurrentSkipListMap<K,V> clone =
+                (ConcurrentSkipListMap<K,V>) super.clone();
+            clone.initialize();
+            clone.buildFromSorted(this);
+            return clone;
         } catch (CloneNotSupportedException e) {
             throw new InternalError();
         }
-
-        clone.initialize();
-        clone.buildFromSorted(this);
-        return clone;
     }
 
     /**
@@ -1458,7 +1477,7 @@
     /* ---------------- Serialization -------------- */
 
     /**
-     * Save the state of this map to a stream.
+     * Saves the state of this map to a stream (that is, serializes it).
      *
      * @serialData The key (Object) and value (Object) for each
      * key-value mapping represented by the map, followed by
@@ -1483,7 +1502,9 @@
     }
 
     /**
-     * Reconstitute the map from a stream.
+     * Reconstitutes the map from a stream (that is, deserializes it).
+     *
+     * @param s the stream
      */
     private void readObject(final java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
@@ -1613,7 +1634,9 @@
     /**
      * Returns <tt>true</tt> if this map maps one or more keys to the
      * specified value.  This operation requires time linear in the
-     * map size.
+     * map size. Additionally, it is possible for the map to change
+     * during execution of this method, in which case the returned
+     * result may be inaccurate.
      *
      * @param value value whose presence in this map is to be tested
      * @return <tt>true</tt> if a mapping to <tt>value</tt> exists;
@@ -1703,14 +1726,14 @@
      *
      * @return a navigable set view of the keys in this map
      */
-     public NavigableSet<K> keySet() {
-        KeySet ks = keySet;
-        return (ks != null) ? ks : (keySet = new KeySet(this));
+    public NavigableSet<K> keySet() {
+        KeySet<K> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet<K>(this));
     }
 
     public NavigableSet<K> navigableKeySet() {
-        KeySet ks = keySet;
-        return (ks != null) ? ks : (keySet = new KeySet(this));
+        KeySet<K> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet<K>(this));
     }
 
     /**
@@ -1732,8 +1755,8 @@
      * reflect any modifications subsequent to construction.
      */
     public Collection<V> values() {
-        Values vs = values;
-        return (vs != null) ? vs : (values = new Values(this));
+        Values<V> vs = values;
+        return (vs != null) ? vs : (values = new Values<V>(this));
     }
 
     /**
@@ -1761,8 +1784,8 @@
      *         sorted in ascending key order
      */
     public Set<Map.Entry<K,V>> entrySet() {
-        EntrySet es = entrySet;
-        return (es != null) ? es : (entrySet = new EntrySet(this));
+        EntrySet<K,V> es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySet<K,V>(this));
     }
 
     public ConcurrentNavigableMap<K,V> descendingMap() {
@@ -2253,8 +2276,8 @@
 
     static final class KeySet<E>
             extends AbstractSet<E> implements NavigableSet<E> {
-        private final ConcurrentNavigableMap<E,Object> m;
-        KeySet(ConcurrentNavigableMap<E,Object> map) { m = map; }
+        private final ConcurrentNavigableMap<E,?> m;
+        KeySet(ConcurrentNavigableMap<E,?> map) { m = map; }
         public int size() { return m.size(); }
         public boolean isEmpty() { return m.isEmpty(); }
         public boolean contains(Object o) { return m.containsKey(o); }
@@ -2268,11 +2291,11 @@
         public E first() { return m.firstKey(); }
         public E last() { return m.lastKey(); }
         public E pollFirst() {
-            Map.Entry<E,Object> e = m.pollFirstEntry();
+            Map.Entry<E,?> e = m.pollFirstEntry();
             return (e == null) ? null : e.getKey();
         }
         public E pollLast() {
-            Map.Entry<E,Object> e = m.pollLastEntry();
+            Map.Entry<E,?> e = m.pollLastEntry();
             return (e == null) ? null : e.getKey();
         }
         public Iterator<E> iterator() {
@@ -2323,20 +2346,20 @@
             return tailSet(fromElement, true);
         }
         public NavigableSet<E> descendingSet() {
-            return new KeySet(m.descendingMap());
+            return new KeySet<E>(m.descendingMap());
         }
     }
 
     static final class Values<E> extends AbstractCollection<E> {
-        private final ConcurrentNavigableMap<Object, E> m;
-        Values(ConcurrentNavigableMap<Object, E> map) {
+        private final ConcurrentNavigableMap<?, E> m;
+        Values(ConcurrentNavigableMap<?, E> map) {
             m = map;
         }
         public Iterator<E> iterator() {
             if (m instanceof ConcurrentSkipListMap)
-                return ((ConcurrentSkipListMap<Object,E>)m).valueIterator();
+                return ((ConcurrentSkipListMap<?,E>)m).valueIterator();
             else
-                return ((SubMap<Object,E>)m).valueIterator();
+                return ((SubMap<?,E>)m).valueIterator();
         }
         public boolean isEmpty() {
             return m.isEmpty();
@@ -2370,14 +2393,14 @@
         public boolean contains(Object o) {
             if (!(o instanceof Map.Entry))
                 return false;
-            Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
             V1 v = m.get(e.getKey());
             return v != null && v.equals(e.getValue());
         }
         public boolean remove(Object o) {
             if (!(o instanceof Map.Entry))
                 return false;
-            Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
             return m.remove(e.getKey(),
                             e.getValue());
         }
@@ -2517,9 +2540,9 @@
             if (lo == null)
                 return m.findFirst();
             else if (loInclusive)
-                return m.findNear(lo, m.GT|m.EQ);
+                return m.findNear(lo, GT|EQ);
             else
-                return m.findNear(lo, m.GT);
+                return m.findNear(lo, GT);
         }
 
         /**
@@ -2530,9 +2553,9 @@
             if (hi == null)
                 return m.findLast();
             else if (hiInclusive)
-                return m.findNear(hi, m.LT|m.EQ);
+                return m.findNear(hi, LT|EQ);
             else
-                return m.findNear(hi, m.LT);
+                return m.findNear(hi, LT);
         }
 
         /**
@@ -2614,15 +2637,15 @@
          */
         private Map.Entry<K,V> getNearEntry(K key, int rel) {
             if (isDescending) { // adjust relation for direction
-                if ((rel & m.LT) == 0)
-                    rel |= m.LT;
+                if ((rel & LT) == 0)
+                    rel |= LT;
                 else
-                    rel &= ~m.LT;
+                    rel &= ~LT;
             }
             if (tooLow(key))
-                return ((rel & m.LT) != 0) ? null : lowestEntry();
+                return ((rel & LT) != 0) ? null : lowestEntry();
             if (tooHigh(key))
-                return ((rel & m.LT) != 0) ? highestEntry() : null;
+                return ((rel & LT) != 0) ? highestEntry() : null;
             for (;;) {
                 Node<K,V> n = m.findNear(key, rel);
                 if (n == null || !inBounds(n.key))
@@ -2637,13 +2660,13 @@
         // Almost the same as getNearEntry, except for keys
         private K getNearKey(K key, int rel) {
             if (isDescending) { // adjust relation for direction
-                if ((rel & m.LT) == 0)
-                    rel |= m.LT;
+                if ((rel & LT) == 0)
+                    rel |= LT;
                 else
-                    rel &= ~m.LT;
+                    rel &= ~LT;
             }
             if (tooLow(key)) {
-                if ((rel & m.LT) == 0) {
+                if ((rel & LT) == 0) {
                     ConcurrentSkipListMap.Node<K,V> n = loNode();
                     if (isBeforeEnd(n))
                         return n.key;
@@ -2651,7 +2674,7 @@
                 return null;
             }
             if (tooHigh(key)) {
-                if ((rel & m.LT) != 0) {
+                if ((rel & LT) != 0) {
                     ConcurrentSkipListMap.Node<K,V> n = hiNode();
                     if (n != null) {
                         K last = n.key;
@@ -2683,7 +2706,7 @@
         public V get(Object key) {
             if (key == null) throw new NullPointerException();
             K k = (K)key;
-            return ((!inBounds(k)) ? null : m.get(k));
+            return (!inBounds(k)) ? null : m.get(k);
         }
 
         public V put(K key, V value) {
@@ -2850,35 +2873,35 @@
         /* ----------------  Relational methods -------------- */
 
         public Map.Entry<K,V> ceilingEntry(K key) {
-            return getNearEntry(key, (m.GT|m.EQ));
+            return getNearEntry(key, GT|EQ);
         }
 
         public K ceilingKey(K key) {
-            return getNearKey(key, (m.GT|m.EQ));
+            return getNearKey(key, GT|EQ);
         }
 
         public Map.Entry<K,V> lowerEntry(K key) {
-            return getNearEntry(key, (m.LT));
+            return getNearEntry(key, LT);
         }
 
         public K lowerKey(K key) {
-            return getNearKey(key, (m.LT));
+            return getNearKey(key, LT);
         }
 
         public Map.Entry<K,V> floorEntry(K key) {
-            return getNearEntry(key, (m.LT|m.EQ));
+            return getNearEntry(key, LT|EQ);
         }
 
         public K floorKey(K key) {
-            return getNearKey(key, (m.LT|m.EQ));
+            return getNearKey(key, LT|EQ);
         }
 
         public Map.Entry<K,V> higherEntry(K key) {
-            return getNearEntry(key, (m.GT));
+            return getNearEntry(key, GT);
         }
 
         public K higherKey(K key) {
-            return getNearKey(key, (m.GT));
+            return getNearKey(key, GT);
         }
 
         public K firstKey() {
@@ -2909,22 +2932,22 @@
 
         public NavigableSet<K> keySet() {
             KeySet<K> ks = keySetView;
-            return (ks != null) ? ks : (keySetView = new KeySet(this));
+            return (ks != null) ? ks : (keySetView = new KeySet<K>(this));
         }
 
         public NavigableSet<K> navigableKeySet() {
             KeySet<K> ks = keySetView;
-            return (ks != null) ? ks : (keySetView = new KeySet(this));
+            return (ks != null) ? ks : (keySetView = new KeySet<K>(this));
         }
 
         public Collection<V> values() {
             Collection<V> vs = valuesView;
-            return (vs != null) ? vs : (valuesView = new Values(this));
+            return (vs != null) ? vs : (valuesView = new Values<V>(this));
         }
 
         public Set<Map.Entry<K,V>> entrySet() {
             Set<Map.Entry<K,V>> es = entrySetView;
-            return (es != null) ? es : (entrySetView = new EntrySet(this));
+            return (es != null) ? es : (entrySetView = new EntrySet<K,V>(this));
         }
 
         public NavigableSet<K> descendingKeySet() {
@@ -3053,20 +3076,16 @@
     }
 
     // Unsafe mechanics
-    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-    private static final long headOffset =
-        objectFieldOffset(UNSAFE, "head", ConcurrentSkipListMap.class);
-
-    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
-                                  String field, Class<?> klazz) {
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long headOffset;
+    static {
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = ConcurrentSkipListMap.class;
+            headOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("head"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
-
 }
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
index d24876f..71431a9 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentSkipListSet.java
@@ -1,12 +1,15 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
 import java.util.*;
-import sun.misc.Unsafe;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
 
 /**
  * A scalable concurrent {@link NavigableSet} implementation based on
@@ -29,12 +32,14 @@
  * <p>Beware that, unlike in most collections, the <tt>size</tt>
  * method is <em>not</em> a constant-time operation. Because of the
  * asynchronous nature of these sets, determining the current number
- * of elements requires a traversal of the elements. Additionally, the
- * bulk operations <tt>addAll</tt>, <tt>removeAll</tt>,
- * <tt>retainAll</tt>, and <tt>containsAll</tt> are <em>not</em>
- * guaranteed to be performed atomically. For example, an iterator
- * operating concurrently with an <tt>addAll</tt> operation might view
- * only some of the added elements.
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations <tt>addAll</tt>,
+ * <tt>removeAll</tt>, <tt>retainAll</tt>, <tt>containsAll</tt>,
+ * <tt>equals</tt>, and <tt>toArray</tt> are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an <tt>addAll</tt> operation might view only some
+ * of the added elements.
  *
  * <p>This class and its iterators implement all of the
  * <em>optional</em> methods of the {@link Set} and {@link Iterator}
@@ -43,10 +48,6 @@
  * because <tt>null</tt> arguments and return values cannot be reliably
  * distinguished from the absence of elements.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
- * Java Collections Framework</a>.
- *
  * @author Doug Lea
  * @param <E> the type of elements maintained by this set
  * @since 1.6
@@ -127,15 +128,15 @@
      * @return a shallow copy of this set
      */
     public ConcurrentSkipListSet<E> clone() {
-        ConcurrentSkipListSet<E> clone = null;
         try {
-            clone = (ConcurrentSkipListSet<E>) super.clone();
-            clone.setMap(new ConcurrentSkipListMap(m));
+            @SuppressWarnings("unchecked")
+            ConcurrentSkipListSet<E> clone =
+                (ConcurrentSkipListSet<E>) super.clone();
+            clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
+            return clone;
         } catch (CloneNotSupportedException e) {
             throw new InternalError();
         }
-
-        return clone;
     }
 
     /* ---------------- Set operations -------------- */
@@ -291,8 +292,8 @@
     public boolean removeAll(Collection<?> c) {
         // Override AbstractSet version to avoid unnecessary call to size()
         boolean modified = false;
-        for (Iterator<?> i = c.iterator(); i.hasNext(); )
-            if (remove(i.next()))
+        for (Object e : c)
+            if (remove(e))
                 modified = true;
         return modified;
     }
@@ -437,20 +438,24 @@
      * @return a reverse order view of this set
      */
     public NavigableSet<E> descendingSet() {
-        return new ConcurrentSkipListSet(m.descendingMap());
+        return new ConcurrentSkipListSet<E>(m.descendingMap());
     }
 
     // Support for resetting map in clone
-    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private void setMap(ConcurrentNavigableMap<E,Object> map) {
+        UNSAFE.putObjectVolatile(this, mapOffset, map);
+    }
+
+    private static final sun.misc.Unsafe UNSAFE;
     private static final long mapOffset;
     static {
         try {
-            mapOffset = unsafe.objectFieldOffset
-                (ConcurrentSkipListSet.class.getDeclaredField("m"));
-        } catch (Exception ex) { throw new Error(ex); }
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = ConcurrentSkipListSet.class;
+            mapOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("m"));
+        } catch (Exception e) {
+            throw new Error(e);
+        }
     }
-    private void setMap(ConcurrentNavigableMap<E,Object> map) {
-        unsafe.putObjectVolatile(this, mapOffset, map);
-    }
-
 }
diff --git a/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java b/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
index 87419fc..1f37bc9 100644
--- a/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
+++ b/luni/src/main/java/java/util/concurrent/CopyOnWriteArraySet.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -160,8 +160,7 @@
      * The following code can be used to dump the set into a newly allocated
      * array of <tt>String</tt>:
      *
-     * <pre>
-     *     String[] y = x.toArray(new String[0]);</pre>
+     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
      *
      * Note that <tt>toArray(new Object[0])</tt> is identical in function to
      * <tt>toArray()</tt>.
@@ -358,6 +357,6 @@
      * Test for equality, coping with nulls.
      */
     private static boolean eq(Object o1, Object o2) {
-        return (o1 == null ? o2 == null : o1.equals(o2));
+        return (o1 == null) ? o2 == null : o1.equals(o2);
     }
 }
diff --git a/luni/src/main/java/java/util/concurrent/CountDownLatch.java b/luni/src/main/java/java/util/concurrent/CountDownLatch.java
index 1888279..e90badf 100644
--- a/luni/src/main/java/java/util/concurrent/CountDownLatch.java
+++ b/luni/src/main/java/java/util/concurrent/CountDownLatch.java
@@ -1,12 +1,11 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
 import java.util.concurrent.locks.*;
-import java.util.concurrent.atomic.*;
 
 /**
  * A synchronization aid that allows one or more threads to wait until
@@ -44,7 +43,7 @@
  * until all workers have completed.
  * </ul>
  *
- * <pre>
+ *  <pre> {@code
  * class Driver { // ...
  *   void main() throws InterruptedException {
  *     CountDownLatch startSignal = new CountDownLatch(1);
@@ -76,9 +75,7 @@
  *   }
  *
  *   void doWork() { ... }
- * }
- *
- * </pre>
+ * }}</pre>
  *
  * <p>Another typical usage would be to divide a problem into N parts,
  * describe each part with a Runnable that executes that portion and
@@ -87,7 +84,7 @@
  * will be able to pass through await. (When threads must repeatedly
  * count down in this way, instead use a {@link CyclicBarrier}.)
  *
- * <pre>
+ *  <pre> {@code
  * class Driver2 { // ...
  *   void main() throws InterruptedException {
  *     CountDownLatch doneSignal = new CountDownLatch(N);
@@ -115,9 +112,7 @@
  *   }
  *
  *   void doWork() { ... }
- * }
- *
- * </pre>
+ * }}</pre>
  *
  * <p>Memory consistency effects: Until the count reaches
  * zero, actions in a thread prior to calling
diff --git a/luni/src/main/java/java/util/concurrent/CyclicBarrier.java b/luni/src/main/java/java/util/concurrent/CyclicBarrier.java
index d5738c5..cf0b46e 100644
--- a/luni/src/main/java/java/util/concurrent/CyclicBarrier.java
+++ b/luni/src/main/java/java/util/concurrent/CyclicBarrier.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -23,7 +23,8 @@
  *
  * <p><b>Sample usage:</b> Here is an example of
  *  using a barrier in a parallel decomposition design:
- * <pre>
+ *
+ *  <pre> {@code
  * class Solver {
  *   final int N;
  *   final float[][] data;
@@ -61,8 +62,8 @@
  *
  *     waitUntilDone();
  *   }
- * }
- * </pre>
+ * }}</pre>
+ *
  * Here, each worker thread processes a row of the matrix then waits at the
  * barrier until all rows have been processed. When all rows are processed
  * the supplied {@link Runnable} barrier action is executed and merges the
@@ -76,9 +77,10 @@
  * {@link #await} returns the arrival index of that thread at the barrier.
  * You can then choose which thread should execute the barrier action, for
  * example:
- * <pre>  if (barrier.await() == 0) {
- *     // log the completion of this iteration
- *   }</pre>
+ *  <pre> {@code
+ * if (barrier.await() == 0) {
+ *   // log the completion of this iteration
+ * }}</pre>
  *
  * <p>The <tt>CyclicBarrier</tt> uses an all-or-none breakage model
  * for failed synchronization attempts: If a thread leaves a barrier
@@ -175,21 +177,21 @@
                 throw new InterruptedException();
             }
 
-           int index = --count;
-           if (index == 0) {  // tripped
-               boolean ranAction = false;
-               try {
-                   final Runnable command = barrierCommand;
-                   if (command != null)
-                       command.run();
-                   ranAction = true;
-                   nextGeneration();
-                   return 0;
-               } finally {
-                   if (!ranAction)
-                       breakBarrier();
-               }
-           }
+            int index = --count;
+            if (index == 0) {  // tripped
+                boolean ranAction = false;
+                try {
+                    final Runnable command = barrierCommand;
+                    if (command != null)
+                        command.run();
+                    ranAction = true;
+                    nextGeneration();
+                    return 0;
+                } finally {
+                    if (!ranAction)
+                        breakBarrier();
+                }
+            }
 
             // loop until tripped, broken, interrupted, or timed out
             for (;;) {
@@ -325,7 +327,7 @@
         try {
             return dowait(false, 0L);
         } catch (TimeoutException toe) {
-            throw new Error(toe); // cannot happen;
+            throw new Error(toe); // cannot happen
         }
     }
 
diff --git a/luni/src/main/java/java/util/concurrent/DelayQueue.java b/luni/src/main/java/java/util/concurrent/DelayQueue.java
index 8c44e82..52028cb 100644
--- a/luni/src/main/java/java/util/concurrent/DelayQueue.java
+++ b/luni/src/main/java/java/util/concurrent/DelayQueue.java
@@ -1,12 +1,14 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 
 package java.util.concurrent;
-import java.util.concurrent.locks.*;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.*;
 
 // BEGIN android-note
@@ -29,7 +31,9 @@
  *
  * <p>This class and its iterator implement all of the
  * <em>optional</em> methods of the {@link Collection} and {@link
- * Iterator} interfaces.
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} is <em>not</em> guaranteed to traverse the elements of
+ * the DelayQueue in any particular order.
  *
  * @since 1.5
  * @author Doug Lea
@@ -154,7 +158,7 @@
         lock.lock();
         try {
             E first = q.peek();
-            if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
+            if (first == null || first.getDelay(NANOSECONDS) > 0)
                 return null;
             else
                 return q.poll();
@@ -179,7 +183,7 @@
                 if (first == null)
                     available.await();
                 else {
-                    long delay = first.getDelay(TimeUnit.NANOSECONDS);
+                    long delay = first.getDelay(NANOSECONDS);
                     if (delay <= 0)
                         return q.poll();
                     else if (leader != null)
@@ -226,7 +230,7 @@
                     else
                         nanos = available.awaitNanos(nanos);
                 } else {
-                    long delay = first.getDelay(TimeUnit.NANOSECONDS);
+                    long delay = first.getDelay(NANOSECONDS);
                     if (delay <= 0)
                         return q.poll();
                     if (nanos <= 0)
@@ -284,6 +288,17 @@
     }
 
     /**
+     * Return first element only if it is expired.
+     * Used only by drainTo.  Call only when holding lock.
+     */
+    private E peekExpired() {
+        // assert lock.isHeldByCurrentThread();
+        E first = q.peek();
+        return (first == null || first.getDelay(NANOSECONDS) > 0) ?
+            null : first;
+    }
+
+    /**
      * @throws UnsupportedOperationException {@inheritDoc}
      * @throws ClassCastException            {@inheritDoc}
      * @throws NullPointerException          {@inheritDoc}
@@ -298,11 +313,9 @@
         lock.lock();
         try {
             int n = 0;
-            for (;;) {
-                E first = q.peek();
-                if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
-                    break;
-                c.add(q.poll());
+            for (E e; (e = peekExpired()) != null;) {
+                c.add(e);       // In this order, in case add() throws.
+                q.poll();
                 ++n;
             }
             return n;
@@ -328,11 +341,9 @@
         lock.lock();
         try {
             int n = 0;
-            while (n < maxElements) {
-                E first = q.peek();
-                if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
-                    break;
-                c.add(q.poll());
+            for (E e; n < maxElements && (e = peekExpired()) != null;) {
+                c.add(e);       // In this order, in case add() throws.
+                q.poll();
                 ++n;
             }
             return n;
@@ -411,8 +422,7 @@
      * <p>The following code can be used to dump a delay queue into a newly
      * allocated array of <tt>Delayed</tt>:
      *
-     * <pre>
-     *     Delayed[] a = q.toArray(new Delayed[0]);</pre>
+     * <pre> {@code Delayed[] a = q.toArray(new Delayed[0]);}</pre>
      *
      * Note that <tt>toArray(new Object[0])</tt> is identical in function to
      * <tt>toArray()</tt>.
@@ -451,6 +461,24 @@
     }
 
     /**
+     * Identity-based version for use in Itr.remove
+     */
+    void removeEQ(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Iterator<E> it = q.iterator(); it.hasNext(); ) {
+                if (o == it.next()) {
+                    it.remove();
+                    break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
      * Returns an iterator over all the elements (both expired and
      * unexpired) in this queue. The iterator does not return the
      * elements in any particular order.
@@ -473,7 +501,7 @@
      */
     private class Itr implements Iterator<E> {
         final Object[] array; // Array of all elements
-        int cursor;           // index of next element to return;
+        int cursor;           // index of next element to return
         int lastRet;          // index of last element, or -1 if no such
 
         Itr(Object[] array) {
@@ -496,21 +524,8 @@
         public void remove() {
             if (lastRet < 0)
                 throw new IllegalStateException();
-            Object x = array[lastRet];
+            removeEQ(array[lastRet]);
             lastRet = -1;
-            // Traverse underlying queue to find == element,
-            // not just a .equals element.
-            lock.lock();
-            try {
-                for (Iterator it = q.iterator(); it.hasNext(); ) {
-                    if (it.next() == x) {
-                        it.remove();
-                        return;
-                    }
-                }
-            } finally {
-                lock.unlock();
-            }
         }
     }
 
diff --git a/luni/src/main/java/java/util/concurrent/Delayed.java b/luni/src/main/java/java/util/concurrent/Delayed.java
index b1ff4ee..39d927c 100644
--- a/luni/src/main/java/java/util/concurrent/Delayed.java
+++ b/luni/src/main/java/java/util/concurrent/Delayed.java
@@ -1,13 +1,11 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
 
-import java.util.*;
-
 /**
  * A mix-in style interface for marking objects that should be
  * acted upon after a given delay.
diff --git a/luni/src/main/java/java/util/concurrent/Exchanger.java b/luni/src/main/java/java/util/concurrent/Exchanger.java
index 3c230be..6069dce 100644
--- a/luni/src/main/java/java/util/concurrent/Exchanger.java
+++ b/luni/src/main/java/java/util/concurrent/Exchanger.java
@@ -2,7 +2,7 @@
  * Written by Doug Lea, Bill Scherer, and Michael Scott with
  * assistance from members of JCP JSR-166 Expert Group and released to
  * the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -23,7 +23,7 @@
  * to swap buffers between threads so that the thread filling the
  * buffer gets a freshly emptied one when it needs it, handing off the
  * filled one to the thread emptying the buffer.
- * <pre>{@code
+ *  <pre> {@code
  * class FillAndEmpty {
  *   Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>();
  *   DataBuffer initialEmptyBuffer = ... a made-up type
@@ -59,8 +59,7 @@
  *     new Thread(new FillingLoop()).start();
  *     new Thread(new EmptyingLoop()).start();
  *   }
- * }
- * }</pre>
+ * }}</pre>
  *
  * <p>Memory consistency effects: For each pair of threads that
  * successfully exchange objects via an {@code Exchanger}, actions
@@ -135,8 +134,8 @@
      * races between two threads or thread pre-emptions occurring
      * between reading and CASing.  Also, very transient peak
      * contention can be much higher than the average sustainable
-     * levels.  The max limit is decreased on average 50% of the times
-     * that a non-slot-zero wait elapses without being fulfilled.
+     * levels.  An attempt to decrease the max limit is usually made
+     * when a non-slot-zero wait elapses without being fulfilled.
      * Threads experiencing elapsed waits move closer to zero, so
      * eventually find existing (or future) threads even if the table
      * has been shrunk due to inactivity.  The chosen mechanics and
@@ -275,7 +274,9 @@
      * extra space.
      */
     private static final class Slot extends AtomicReference<Object> {
-        // Improve likelihood of isolation on <= 64 byte cache lines
+        // Improve likelihood of isolation on <= 128 byte cache lines.
+        // We used to target 64 byte cache lines, but some x86s (including
+        // i7 under some BIOSes) actually use 128 byte cache lines.
         long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, qa, qb, qc, qd, qe;
     }
 
diff --git a/luni/src/main/java/java/util/concurrent/ExecutionException.java b/luni/src/main/java/java/util/concurrent/ExecutionException.java
index bc561e5..9bb8dee 100644
--- a/luni/src/main/java/java/util/concurrent/ExecutionException.java
+++ b/luni/src/main/java/java/util/concurrent/ExecutionException.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -50,11 +50,9 @@
 
     /**
      * Constructs an <tt>ExecutionException</tt> with the specified cause.
-     * The detail message is set to:
-     * <pre>
-     *  (cause == null ? null : cause.toString())</pre>
-     * (which typically contains the class and detail message of
-     * <tt>cause</tt>).
+     * The detail message is set to {@code (cause == null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of <tt>cause</tt>).
      *
      * @param  cause the cause (which is saved for later retrieval by the
      *         {@link #getCause()} method)
diff --git a/luni/src/main/java/java/util/concurrent/Executor.java b/luni/src/main/java/java/util/concurrent/Executor.java
index fbc4e6f..831bf46 100644
--- a/luni/src/main/java/java/util/concurrent/Executor.java
+++ b/luni/src/main/java/java/util/concurrent/Executor.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -27,23 +27,23 @@
  * executor can run the submitted task immediately in the caller's
  * thread:
  *
- * <pre>
+ *  <pre> {@code
  * class DirectExecutor implements Executor {
- *     public void execute(Runnable r) {
- *         r.run();
- *     }
- * }</pre>
+ *   public void execute(Runnable r) {
+ *     r.run();
+ *   }
+ * }}</pre>
  *
  * More typically, tasks are executed in some thread other
  * than the caller's thread.  The executor below spawns a new thread
  * for each task.
  *
- * <pre>
+ *  <pre> {@code
  * class ThreadPerTaskExecutor implements Executor {
- *     public void execute(Runnable r) {
- *         new Thread(r).start();
- *     }
- * }</pre>
+ *   public void execute(Runnable r) {
+ *     new Thread(r).start();
+ *   }
+ * }}</pre>
  *
  * Many <tt>Executor</tt> implementations impose some sort of
  * limitation on how and when tasks are scheduled.  The executor below
diff --git a/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java b/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
index b41955d..c0d6006 100644
--- a/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
+++ b/luni/src/main/java/java/util/concurrent/ExecutorCompletionService.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/ExecutorService.java b/luni/src/main/java/java/util/concurrent/ExecutorService.java
index 89688e4..a33ceec 100644
--- a/luni/src/main/java/java/util/concurrent/ExecutorService.java
+++ b/luni/src/main/java/java/util/concurrent/ExecutorService.java
@@ -1,14 +1,16 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
 import java.util.List;
 import java.util.Collection;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedExceptionAction;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
 
 /**
  * An {@link Executor} that provides methods to manage termination and
@@ -44,7 +46,7 @@
  * pool service incoming requests. It uses the preconfigured {@link
  * Executors#newFixedThreadPool} factory method:
  *
- * <pre>
+ *  <pre> {@code
  * class NetworkService implements Runnable {
  *   private final ServerSocket serverSocket;
  *   private final ExecutorService pool;
@@ -72,14 +74,13 @@
  *   public void run() {
  *     // read and service request on socket
  *   }
- * }
- * </pre>
+ * }}</pre>
  *
  * The following method shuts down an <tt>ExecutorService</tt> in two phases,
  * first by calling <tt>shutdown</tt> to reject incoming tasks, and then
  * calling <tt>shutdownNow</tt>, if necessary, to cancel any lingering tasks:
  *
- * <pre>
+ *  <pre> {@code
  * void shutdownAndAwaitTermination(ExecutorService pool) {
  *   pool.shutdown(); // Disable new tasks from being submitted
  *   try {
@@ -96,8 +97,7 @@
  *     // Preserve interrupt status
  *     Thread.currentThread().interrupt();
  *   }
- * }
- * </pre>
+ * }}</pre>
  *
  * <p>Memory consistency effects: Actions in a thread prior to the
  * submission of a {@code Runnable} or {@code Callable} task to an
diff --git a/luni/src/main/java/java/util/concurrent/Executors.java b/luni/src/main/java/java/util/concurrent/Executors.java
index e42b0cc..b4f03ba 100644
--- a/luni/src/main/java/java/util/concurrent/Executors.java
+++ b/luni/src/main/java/java/util/concurrent/Executors.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -12,9 +12,10 @@
 import java.security.PrivilegedAction;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedActionException;
-import java.security.AccessControlException;
-// import sun.security.util.SecurityConstants; // android-removed
 
+// BEGIN android-note
+// removed security manager docs
+// END android-note
 /**
  * Factory and utility methods for {@link Executor}, {@link
  * ExecutorService}, {@link ScheduledExecutorService}, {@link
@@ -271,10 +272,7 @@
     /**
      * Returns a default thread factory used to create new threads.
      * This factory creates all new threads used by an Executor in the
-     * same {@link ThreadGroup}. If there is a {@link
-     * java.lang.SecurityManager}, it uses the group of {@link
-     * System#getSecurityManager}, else the group of the thread
-     * invoking this <tt>defaultThreadFactory</tt> method. Each new
+     * same {@link ThreadGroup}. Each new
      * thread is created as a non-daemon thread with priority set to
      * the smaller of <tt>Thread.NORM_PRIORITY</tt> and the maximum
      * priority permitted in the thread group.  New threads have names
@@ -289,36 +287,7 @@
     }
 
     /**
-     * Returns a thread factory used to create new threads that
-     * have the same permissions as the current thread.
-     * This factory creates threads with the same settings as {@link
-     * Executors#defaultThreadFactory}, additionally setting the
-     * AccessControlContext and contextClassLoader of new threads to
-     * be the same as the thread invoking this
-     * <tt>privilegedThreadFactory</tt> method.  A new
-     * <tt>privilegedThreadFactory</tt> can be created within an
-     * {@link AccessController#doPrivileged} action setting the
-     * current thread's access control context to create threads with
-     * the selected permission settings holding within that action.
-     *
-     * <p> Note that while tasks running within such threads will have
-     * the same access control and class loader settings as the
-     * current thread, they need not have the same {@link
-     * java.lang.ThreadLocal} or {@link
-     * java.lang.InheritableThreadLocal} values. If necessary,
-     * particular values of thread locals can be set or reset before
-     * any task runs in {@link ThreadPoolExecutor} subclasses using
-     * {@link ThreadPoolExecutor#beforeExecute}. Also, if it is
-     * necessary to initialize worker threads to have the same
-     * InheritableThreadLocal settings as some other designated
-     * thread, you can create a custom ThreadFactory in which that
-     * thread waits for and services requests to create others that
-     * will inherit its values.
-     *
-     * @return a thread factory
-     * @throws AccessControlException if the current access control
-     * context does not have permission to both get and set context
-     * class loader.
+     * Legacy security code; do not use.
      */
     public static ThreadFactory privilegedThreadFactory() {
         return new PrivilegedThreadFactory();
@@ -383,18 +352,7 @@
     }
 
     /**
-     * Returns a {@link Callable} object that will, when
-     * called, execute the given <tt>callable</tt> under the current
-     * access control context. This method should normally be
-     * invoked within an {@link AccessController#doPrivileged} action
-     * to create callables that will, if possible, execute under the
-     * selected permission settings holding within that action; or if
-     * not possible, throw an associated {@link
-     * AccessControlException}.
-     * @param callable the underlying task
-     * @return a callable object
-     * @throws NullPointerException if callable null
-     *
+     * Legacy security code; do not use.
      */
     public static <T> Callable<T> privilegedCallable(Callable<T> callable) {
         if (callable == null)
@@ -405,20 +363,10 @@
     /**
      * Returns a {@link Callable} object that will, when
      * called, execute the given <tt>callable</tt> under the current
-     * access control context, with the current context class loader
-     * as the context class loader. This method should normally be
-     * invoked within an {@link AccessController#doPrivileged} action
-     * to create callables that will, if possible, execute under the
-     * selected permission settings holding within that action; or if
-     * not possible, throw an associated {@link
-     * AccessControlException}.
-     * @param callable the underlying task
+     * with the current context class loader as the context class loader.
      *
      * @return a callable object
      * @throws NullPointerException if callable null
-     * @throws AccessControlException if the current access control
-     * context does not have permission to both set and get context
-     * class loader.
      */
     public static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable) {
         if (callable == null)
@@ -480,17 +428,19 @@
         private final ClassLoader ccl;
 
         PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                // Calls to getContextClassLoader from this class
-                // never trigger a security check, but we check
-                // whether our callers have this permission anyways.
-                sm.checkPermission(new RuntimePermission("getContextClassLoader")); // android-changed
-
-                // Whether setContextClassLoader turns out to be necessary
-                // or not, we fail fast if permission is not available.
-                sm.checkPermission(new RuntimePermission("setContextClassLoader"));
-            }
+            // BEGIN android-removed
+            // SecurityManager sm = System.getSecurityManager();
+            // if (sm != null) {
+            //     // Calls to getContextClassLoader from this class
+            //     // never trigger a security check, but we check
+            //     // whether our callers have this permission anyways.
+            //     sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+            //
+            //     // Whether setContextClassLoader turns out to be necessary
+            //     // or not, we fail fast if permission is not available.
+            //     sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+            // }
+            // END android-removed
             this.task = task;
             this.acc = AccessController.getContext();
             this.ccl = Thread.currentThread().getContextClassLoader();
@@ -561,16 +511,18 @@
 
         PrivilegedThreadFactory() {
             super();
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                // Calls to getContextClassLoader from this class
-                // never trigger a security check, but we check
-                // whether our callers have this permission anyways.
-                sm.checkPermission(new RuntimePermission("getContextClassLoader")); // android-changed
-
-                // Fail fast
-                sm.checkPermission(new RuntimePermission("setContextClassLoader"));
-            }
+            // BEGIN android-removed
+            // SecurityManager sm = System.getSecurityManager();
+            // if (sm != null) {
+            //     // Calls to getContextClassLoader from this class
+            //     // never trigger a security check, but we check
+            //     // whether our callers have this permission anyways.
+            //     sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+            //
+            //     // Fail fast
+            //     sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+            // }
+            // END android-removed
             this.acc = AccessController.getContext();
             this.ccl = Thread.currentThread().getContextClassLoader();
         }
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
new file mode 100644
index 0000000..ee15ac8
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
@@ -0,0 +1,2127 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Condition;
+import libcore.util.SneakyThrow;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
+/**
+ * An {@link ExecutorService} for running {@link ForkJoinTask}s.
+ * A {@code ForkJoinPool} provides the entry point for submissions
+ * from non-{@code ForkJoinTask} clients, as well as management and
+ * monitoring operations.
+ *
+ * <p>A {@code ForkJoinPool} differs from other kinds of {@link
+ * ExecutorService} mainly by virtue of employing
+ * <em>work-stealing</em>: all threads in the pool attempt to find and
+ * execute subtasks created by other active tasks (eventually blocking
+ * waiting for work if none exist). This enables efficient processing
+ * when most tasks spawn other subtasks (as do most {@code
+ * ForkJoinTask}s). When setting <em>asyncMode</em> to true in
+ * constructors, {@code ForkJoinPool}s may also be appropriate for use
+ * with event-style tasks that are never joined.
+ *
+ * <p>A {@code ForkJoinPool} is constructed with a given target
+ * parallelism level; by default, equal to the number of available
+ * processors. The pool attempts to maintain enough active (or
+ * available) threads by dynamically adding, suspending, or resuming
+ * internal worker threads, even if some tasks are stalled waiting to
+ * join others. However, no such adjustments are guaranteed in the
+ * face of blocked IO or other unmanaged synchronization. The nested
+ * {@link ManagedBlocker} interface enables extension of the kinds of
+ * synchronization accommodated.
+ *
+ * <p>In addition to execution and lifecycle control methods, this
+ * class provides status check methods (for example
+ * {@link #getStealCount}) that are intended to aid in developing,
+ * tuning, and monitoring fork/join applications. Also, method
+ * {@link #toString} returns indications of pool state in a
+ * convenient form for informal monitoring.
+ *
+ * <p> As is the case with other ExecutorServices, there are three
+ * main task execution methods summarized in the following
+ * table. These are designed to be used by clients not already engaged
+ * in fork/join computations in the current pool.  The main forms of
+ * these methods accept instances of {@code ForkJoinTask}, but
+ * overloaded forms also allow mixed execution of plain {@code
+ * Runnable}- or {@code Callable}- based activities as well.  However,
+ * tasks that are already executing in a pool should normally
+ * <em>NOT</em> use these pool execution methods, but instead use the
+ * within-computation forms listed in the table.
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td>
+ *    <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td> <b>Arrange async execution</td>
+ *    <td> {@link #execute(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#fork}</td>
+ *  </tr>
+ *  <tr>
+ *    <td> <b>Await and obtain result</td>
+ *    <td> {@link #invoke(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#invoke}</td>
+ *  </tr>
+ *  <tr>
+ *    <td> <b>Arrange exec and obtain Future</td>
+ *    <td> {@link #submit(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td>
+ *  </tr>
+ * </table>
+ *
+ * <p><b>Sample Usage.</b> Normally a single {@code ForkJoinPool} is
+ * used for all parallel task execution in a program or subsystem.
+ * Otherwise, use would not usually outweigh the construction and
+ * bookkeeping overhead of creating a large set of threads. For
+ * example, a common pool could be used for the {@code SortTasks}
+ * illustrated in {@link RecursiveAction}. Because {@code
+ * ForkJoinPool} uses threads in {@linkplain java.lang.Thread#isDaemon
+ * daemon} mode, there is typically no need to explicitly {@link
+ * #shutdown} such a pool upon program exit.
+ *
+ *  <pre> {@code
+ * static final ForkJoinPool mainPool = new ForkJoinPool();
+ * ...
+ * public void sort(long[] array) {
+ *   mainPool.invoke(new SortTask(array, 0, array.length));
+ * }}</pre>
+ *
+ * <p><b>Implementation notes</b>: This implementation restricts the
+ * maximum number of running threads to 32767. Attempts to create
+ * pools with greater than the maximum number result in
+ * {@code IllegalArgumentException}.
+ *
+ * <p>This implementation rejects submitted tasks (that is, by throwing
+ * {@link RejectedExecutionException}) only when the pool is shut down
+ * or internal resources have been exhausted.
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ */
+public class ForkJoinPool extends AbstractExecutorService {
+
+    /*
+     * Implementation Overview
+     *
+     * This class provides the central bookkeeping and control for a
+     * set of worker threads: Submissions from non-FJ threads enter
+     * into a submission queue. Workers take these tasks and typically
+     * split them into subtasks that may be stolen by other workers.
+     * Preference rules give first priority to processing tasks from
+     * their own queues (LIFO or FIFO, depending on mode), then to
+     * randomized FIFO steals of tasks in other worker queues, and
+     * lastly to new submissions.
+     *
+     * The main throughput advantages of work-stealing stem from
+     * decentralized control -- workers mostly take tasks from
+     * themselves or each other. We cannot negate this in the
+     * implementation of other management responsibilities. The main
+     * tactic for avoiding bottlenecks is packing nearly all
+     * essentially atomic control state into a single 64bit volatile
+     * variable ("ctl"). This variable is read on the order of 10-100
+     * times as often as it is modified (always via CAS). (There is
+     * some additional control state, for example variable "shutdown"
+     * for which we can cope with uncoordinated updates.)  This
+     * streamlines synchronization and control at the expense of messy
+     * constructions needed to repack status bits upon updates.
+     * Updates tend not to contend with each other except during
+     * bursts while submitted tasks begin or end.  In some cases when
+     * they do contend, threads can instead do something else
+     * (usually, scan for tasks) until contention subsides.
+     *
+     * To enable packing, we restrict maximum parallelism to (1<<15)-1
+     * (which is far in excess of normal operating range) to allow
+     * ids, counts, and their negations (used for thresholding) to fit
+     * into 16bit fields.
+     *
+     * Recording Workers.  Workers are recorded in the "workers" array
+     * that is created upon pool construction and expanded if (rarely)
+     * necessary.  This is an array as opposed to some other data
+     * structure to support index-based random steals by workers.
+     * Updates to the array recording new workers and unrecording
+     * terminated ones are protected from each other by a seqLock
+     * (scanGuard) but the array is otherwise concurrently readable,
+     * and accessed directly by workers. To simplify index-based
+     * operations, the array size is always a power of two, and all
+     * readers must tolerate null slots. To avoid flailing during
+     * start-up, the array is presized to hold twice #parallelism
+     * workers (which is unlikely to need further resizing during
+     * execution). But to avoid dealing with so many null slots,
+     * variable scanGuard includes a mask for the nearest power of two
+     * that contains all current workers.  All worker thread creation
+     * is on-demand, triggered by task submissions, replacement of
+     * terminated workers, and/or compensation for blocked
+     * workers. However, all other support code is set up to work with
+     * other policies.  To ensure that we do not hold on to worker
+     * references that would prevent GC, ALL accesses to workers are
+     * via indices into the workers array (which is one source of some
+     * of the messy code constructions here). In essence, the workers
+     * array serves as a weak reference mechanism. Thus for example
+     * the wait queue field of ctl stores worker indices, not worker
+     * references.  Access to the workers in associated methods (for
+     * example signalWork) must both index-check and null-check the
+     * IDs. All such accesses ignore bad IDs by returning out early
+     * from what they are doing, since this can only be associated
+     * with termination, in which case it is OK to give up.
+     *
+     * All uses of the workers array, as well as queue arrays, check
+     * that the array is non-null (even if previously non-null). This
+     * allows nulling during termination, which is currently not
+     * necessary, but remains an option for resource-revocation-based
+     * shutdown schemes.
+     *
+     * Wait Queuing. Unlike HPC work-stealing frameworks, we cannot
+     * let workers spin indefinitely scanning for tasks when none can
+     * be found immediately, and we cannot start/resume workers unless
+     * there appear to be tasks available.  On the other hand, we must
+     * quickly prod them into action when new tasks are submitted or
+     * generated.  We park/unpark workers after placing in an event
+     * wait queue when they cannot find work. This "queue" is actually
+     * a simple Treiber stack, headed by the "id" field of ctl, plus a
+     * 15bit counter value to both wake up waiters (by advancing their
+     * count) and avoid ABA effects. Successors are held in worker
+     * field "nextWait".  Queuing deals with several intrinsic races,
+     * mainly that a task-producing thread can miss seeing (and
+     * signalling) another thread that gave up looking for work but
+     * has not yet entered the wait queue. We solve this by requiring
+     * a full sweep of all workers both before (in scan()) and after
+     * (in tryAwaitWork()) a newly waiting worker is added to the wait
+     * queue. During a rescan, the worker might release some other
+     * queued worker rather than itself, which has the same net
+     * effect. Because enqueued workers may actually be rescanning
+     * rather than waiting, we set and clear the "parked" field of
+     * ForkJoinWorkerThread to reduce unnecessary calls to unpark.
+     * (Use of the parked field requires a secondary recheck to avoid
+     * missed signals.)
+     *
+     * Signalling.  We create or wake up workers only when there
+     * appears to be at least one task they might be able to find and
+     * execute.  When a submission is added or another worker adds a
+     * task to a queue that previously had two or fewer tasks, they
+     * signal waiting workers (or trigger creation of new ones if
+     * fewer than the given parallelism level -- see signalWork).
+     * These primary signals are buttressed by signals during rescans
+     * as well as those performed when a worker steals a task and
+     * notices that there are more tasks too; together these cover the
+     * signals needed in cases when more than two tasks are pushed
+     * but untaken.
+     *
+     * Trimming workers. To release resources after periods of lack of
+     * use, a worker starting to wait when the pool is quiescent will
+     * time out and terminate if the pool has remained quiescent for
+     * SHRINK_RATE nanosecs. This will slowly propagate, eventually
+     * terminating all workers after long periods of non-use.
+     *
+     * Submissions. External submissions are maintained in an
+     * array-based queue that is structured identically to
+     * ForkJoinWorkerThread queues except for the use of
+     * submissionLock in method addSubmission. Unlike the case for
+     * worker queues, multiple external threads can add new
+     * submissions, so adding requires a lock.
+     *
+     * Compensation. Beyond work-stealing support and lifecycle
+     * control, the main responsibility of this framework is to take
+     * actions when one worker is waiting to join a task stolen (or
+     * always held by) another.  Because we are multiplexing many
+     * tasks on to a pool of workers, we can't just let them block (as
+     * in Thread.join).  We also cannot just reassign the joiner's
+     * run-time stack with another and replace it later, which would
+     * be a form of "continuation", that even if possible is not
+     * necessarily a good idea since we sometimes need both an
+     * unblocked task and its continuation to progress. Instead we
+     * combine two tactics:
+     *
+     *   Helping: Arranging for the joiner to execute some task that it
+     *      would be running if the steal had not occurred.  Method
+     *      ForkJoinWorkerThread.joinTask tracks joining->stealing
+     *      links to try to find such a task.
+     *
+     *   Compensating: Unless there are already enough live threads,
+     *      method tryPreBlock() may create or re-activate a spare
+     *      thread to compensate for blocked joiners until they
+     *      unblock.
+     *
+     * The ManagedBlocker extension API can't use helping so relies
+     * only on compensation in method awaitBlocker.
+     *
+     * It is impossible to keep exactly the target parallelism number
+     * of threads running at any given time.  Determining the
+     * existence of conservatively safe helping targets, the
+     * availability of already-created spares, and the apparent need
+     * to create new spares are all racy and require heuristic
+     * guidance, so we rely on multiple retries of each.  Currently,
+     * in keeping with on-demand signalling policy, we compensate only
+     * if blocking would leave less than one active (non-waiting,
+     * non-blocked) worker. Additionally, to avoid some false alarms
+     * due to GC, lagging counters, system activity, etc, compensated
+     * blocking for joins is only attempted after rechecks stabilize
+     * (retries are interspersed with Thread.yield, for good
+     * citizenship).  The variable blockedCount, incremented before
+     * blocking and decremented after, is sometimes needed to
+     * distinguish cases of waiting for work vs blocking on joins or
+     * other managed sync. Both cases are equivalent for most pool
+     * control, so we can update non-atomically. (Additionally,
+     * contention on blockedCount alleviates some contention on ctl).
+     *
+     * Shutdown and Termination. A call to shutdownNow atomically sets
+     * the ctl stop bit and then (non-atomically) sets each workers
+     * "terminate" status, cancels all unprocessed tasks, and wakes up
+     * all waiting workers.  Detecting whether termination should
+     * commence after a non-abrupt shutdown() call requires more work
+     * and bookkeeping. We need consensus about quiescence (i.e., that
+     * there is no more work) which is reflected in active counts so
+     * long as there are no current blockers, as well as possible
+     * re-evaluations during independent changes in blocking or
+     * quiescing workers.
+     *
+     * Style notes: There is a lot of representation-level coupling
+     * among classes ForkJoinPool, ForkJoinWorkerThread, and
+     * ForkJoinTask.  Most fields of ForkJoinWorkerThread maintain
+     * data structures managed by ForkJoinPool, so are directly
+     * accessed.  Conversely we allow access to "workers" array by
+     * workers, and direct access to ForkJoinTask.status by both
+     * ForkJoinPool and ForkJoinWorkerThread.  There is little point
+     * trying to reduce this, since any associated future changes in
+     * representations will need to be accompanied by algorithmic
+     * changes anyway. All together, these low-level implementation
+     * choices produce as much as a factor of 4 performance
+     * improvement compared to naive implementations, and enable the
+     * processing of billions of tasks per second, at the expense of
+     * some ugliness.
+     *
+     * Methods signalWork() and scan() are the main bottlenecks so are
+     * especially heavily micro-optimized/mangled.  There are lots of
+     * inline assignments (of form "while ((local = field) != 0)")
+     * which are usually the simplest way to ensure the required read
+     * orderings (which are sometimes critical). This leads to a
+     * "C"-like style of listing declarations of these locals at the
+     * heads of methods or blocks.  There are several occurrences of
+     * the unusual "do {} while (!cas...)"  which is the simplest way
+     * to force an update of a CAS'ed variable. There are also other
+     * coding oddities that help some methods perform reasonably even
+     * when interpreted (not compiled).
+     *
+     * The order of declarations in this file is: (1) declarations of
+     * statics (2) fields (along with constants used when unpacking
+     * some of them), listed in an order that tends to reduce
+     * contention among them a bit under most JVMs.  (3) internal
+     * control methods (4) callbacks and other support for
+     * ForkJoinTask and ForkJoinWorkerThread classes, (5) exported
+     * methods (plus a few little helpers). (6) static block
+     * initializing all statics in a minimally dependent order.
+     */
+
+    /**
+     * Factory for creating new {@link ForkJoinWorkerThread}s.
+     * A {@code ForkJoinWorkerThreadFactory} must be defined and used
+     * for {@code ForkJoinWorkerThread} subclasses that extend base
+     * functionality or initialize threads with different contexts.
+     */
+    public static interface ForkJoinWorkerThreadFactory {
+        /**
+         * Returns a new worker thread operating in the given pool.
+         *
+         * @param pool the pool this thread works in
+         * @throws NullPointerException if the pool is null
+         */
+        public ForkJoinWorkerThread newThread(ForkJoinPool pool);
+    }
+
+    /**
+     * Default ForkJoinWorkerThreadFactory implementation; creates a
+     * new ForkJoinWorkerThread.
+     */
+    static class DefaultForkJoinWorkerThreadFactory
+        implements ForkJoinWorkerThreadFactory {
+        public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+            return new ForkJoinWorkerThread(pool);
+        }
+    }
+
+    /**
+     * Creates a new ForkJoinWorkerThread. This factory is used unless
+     * overridden in ForkJoinPool constructors.
+     */
+    public static final ForkJoinWorkerThreadFactory
+        defaultForkJoinWorkerThreadFactory;
+
+    /**
+     * Permission required for callers of methods that may start or
+     * kill threads.
+     */
+    private static final RuntimePermission modifyThreadPermission;
+
+    /**
+     * If there is a security manager, makes sure caller has
+     * permission to modify threads.
+     */
+    private static void checkPermission() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(modifyThreadPermission);
+    }
+
+    /**
+     * Generator for assigning sequence numbers as pool names.
+     */
+    private static final AtomicInteger poolNumberGenerator;
+
+    /**
+     * Generator for initial random seeds for worker victim
+     * selection. This is used only to create initial seeds. Random
+     * steals use a cheaper xorshift generator per steal attempt. We
+     * don't expect much contention on seedGenerator, so just use a
+     * plain Random.
+     */
+    static final Random workerSeedGenerator;
+
+    /**
+     * Array holding all worker threads in the pool.  Initialized upon
+     * construction. Array size must be a power of two.  Updates and
+     * replacements are protected by scanGuard, but the array is
+     * always kept in a consistent enough state to be randomly
+     * accessed without locking by workers performing work-stealing,
+     * as well as other traversal-based methods in this class, so long
+     * as reads memory-acquire by first reading ctl. All readers must
+     * tolerate that some array slots may be null.
+     */
+    ForkJoinWorkerThread[] workers;
+
+    /**
+     * Initial size for submission queue array. Must be a power of
+     * two.  In many applications, these always stay small so we use a
+     * small initial cap.
+     */
+    private static final int INITIAL_QUEUE_CAPACITY = 8;
+
+    /**
+     * Maximum size for submission queue array. Must be a power of two
+     * less than or equal to 1 << (31 - width of array entry) to
+     * ensure lack of index wraparound, but is capped at a lower
+     * value to help users trap runaway computations.
+     */
+    private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 24; // 16M
+
+    /**
+     * Array serving as submission queue. Initialized upon construction.
+     */
+    private ForkJoinTask<?>[] submissionQueue;
+
+    /**
+     * Lock protecting submissions array for addSubmission
+     */
+    private final ReentrantLock submissionLock;
+
+    /**
+     * Condition for awaitTermination, using submissionLock for
+     * convenience.
+     */
+    private final Condition termination;
+
+    /**
+     * Creation factory for worker threads.
+     */
+    private final ForkJoinWorkerThreadFactory factory;
+
+    /**
+     * The uncaught exception handler used when any worker abruptly
+     * terminates.
+     */
+    final Thread.UncaughtExceptionHandler ueh;
+
+    /**
+     * Prefix for assigning names to worker threads
+     */
+    private final String workerNamePrefix;
+
+    /**
+     * Sum of per-thread steal counts, updated only when threads are
+     * idle or terminating.
+     */
+    private volatile long stealCount;
+
+    /**
+     * Main pool control -- a long packed with:
+     * AC: Number of active running workers minus target parallelism (16 bits)
+     * TC: Number of total workers minus target parallelism (16 bits)
+     * ST: true if pool is terminating (1 bit)
+     * EC: the wait count of top waiting thread (15 bits)
+     * ID: ~poolIndex of top of Treiber stack of waiting threads (16 bits)
+     *
+     * When convenient, we can extract the upper 32 bits of counts and
+     * the lower 32 bits of queue state, u = (int)(ctl >>> 32) and e =
+     * (int)ctl.  The ec field is never accessed alone, but always
+     * together with id and st. The offsets of counts by the target
+     * parallelism and the positionings of fields makes it possible to
+     * perform the most common checks via sign tests of fields: When
+     * ac is negative, there are not enough active workers, when tc is
+     * negative, there are not enough total workers, when id is
+     * negative, there is at least one waiting worker, and when e is
+     * negative, the pool is terminating.  To deal with these possibly
+     * negative fields, we use casts in and out of "short" and/or
+     * signed shifts to maintain signedness.
+     */
+    volatile long ctl;
+
+    // bit positions/shifts for fields
+    private static final int  AC_SHIFT   = 48;
+    private static final int  TC_SHIFT   = 32;
+    private static final int  ST_SHIFT   = 31;
+    private static final int  EC_SHIFT   = 16;
+
+    // bounds
+    private static final int  MAX_ID     = 0x7fff;  // max poolIndex
+    private static final int  SMASK      = 0xffff;  // mask short bits
+    private static final int  SHORT_SIGN = 1 << 15;
+    private static final int  INT_SIGN   = 1 << 31;
+
+    // masks
+    private static final long STOP_BIT   = 0x0001L << ST_SHIFT;
+    private static final long AC_MASK    = ((long)SMASK) << AC_SHIFT;
+    private static final long TC_MASK    = ((long)SMASK) << TC_SHIFT;
+
+    // units for incrementing and decrementing
+    private static final long TC_UNIT    = 1L << TC_SHIFT;
+    private static final long AC_UNIT    = 1L << AC_SHIFT;
+
+    // masks and units for dealing with u = (int)(ctl >>> 32)
+    private static final int  UAC_SHIFT  = AC_SHIFT - 32;
+    private static final int  UTC_SHIFT  = TC_SHIFT - 32;
+    private static final int  UAC_MASK   = SMASK << UAC_SHIFT;
+    private static final int  UTC_MASK   = SMASK << UTC_SHIFT;
+    private static final int  UAC_UNIT   = 1 << UAC_SHIFT;
+    private static final int  UTC_UNIT   = 1 << UTC_SHIFT;
+
+    // masks and units for dealing with e = (int)ctl
+    private static final int  E_MASK     = 0x7fffffff; // no STOP_BIT
+    private static final int  EC_UNIT    = 1 << EC_SHIFT;
+
+    /**
+     * The target parallelism level.
+     */
+    final int parallelism;
+
+    /**
+     * Index (mod submission queue length) of next element to take
+     * from submission queue. Usage is identical to that for
+     * per-worker queues -- see ForkJoinWorkerThread internal
+     * documentation.
+     */
+    volatile int queueBase;
+
+    /**
+     * Index (mod submission queue length) of next element to add
+     * in submission queue. Usage is identical to that for
+     * per-worker queues -- see ForkJoinWorkerThread internal
+     * documentation.
+     */
+    int queueTop;
+
+    /**
+     * True when shutdown() has been called.
+     */
+    volatile boolean shutdown;
+
+    /**
+     * True if use local fifo, not default lifo, for local polling.
+     * Read by, and replicated by ForkJoinWorkerThreads.
+     */
+    final boolean locallyFifo;
+
+    /**
+     * The number of threads in ForkJoinWorkerThreads.helpQuiescePool.
+     * When non-zero, suppresses automatic shutdown when active
+     * counts become zero.
+     */
+    volatile int quiescerCount;
+
+    /**
+     * The number of threads blocked in join.
+     */
+    volatile int blockedCount;
+
+    /**
+     * Counter for worker Thread names (unrelated to their poolIndex)
+     */
+    private volatile int nextWorkerNumber;
+
+    /**
+     * The index for the next created worker. Accessed under scanGuard.
+     */
+    private int nextWorkerIndex;
+
+    /**
+     * SeqLock and index masking for updates to workers array.  Locked
+     * when SG_UNIT is set. Unlocking clears bit by adding
+     * SG_UNIT. Staleness of read-only operations can be checked by
+     * comparing scanGuard to value before the reads. The low 16 bits
+     * (i.e, anding with SMASK) hold (the smallest power of two
+     * covering all worker indices, minus one, and is used to avoid
+     * dealing with large numbers of null slots when the workers array
+     * is overallocated.
+     */
+    volatile int scanGuard;
+
+    private static final int SG_UNIT = 1 << 16;
+
+    /**
+     * The wakeup interval (in nanoseconds) for a worker waiting for a
+     * task when the pool is quiescent to instead try to shrink the
+     * number of workers.  The exact value does not matter too
+     * much. It must be short enough to release resources during
+     * sustained periods of idleness, but not so short that threads
+     * are continually re-created.
+     */
+    private static final long SHRINK_RATE =
+        4L * 1000L * 1000L * 1000L; // 4 seconds
+
+    /**
+     * Top-level loop for worker threads: On each step: if the
+     * previous step swept through all queues and found no tasks, or
+     * there are excess threads, then possibly blocks. Otherwise,
+     * scans for and, if found, executes a task. Returns when pool
+     * and/or worker terminate.
+     *
+     * @param w the worker
+     */
+    final void work(ForkJoinWorkerThread w) {
+        boolean swept = false;                // true on empty scans
+        long c;
+        while (!w.terminate && (int)(c = ctl) >= 0) {
+            int a;                            // active count
+            if (!swept && (a = (int)(c >> AC_SHIFT)) <= 0)
+                swept = scan(w, a);
+            else if (tryAwaitWork(w, c))
+                swept = false;
+        }
+    }
+
+    // Signalling
+
+    /**
+     * Wakes up or creates a worker.
+     */
+    final void signalWork() {
+        /*
+         * The while condition is true if: (there is are too few total
+         * workers OR there is at least one waiter) AND (there are too
+         * few active workers OR the pool is terminating).  The value
+         * of e distinguishes the remaining cases: zero (no waiters)
+         * for create, negative if terminating (in which case do
+         * nothing), else release a waiter. The secondary checks for
+         * release (non-null array etc) can fail if the pool begins
+         * terminating after the test, and don't impose any added cost
+         * because JVMs must perform null and bounds checks anyway.
+         */
+        long c; int e, u;
+        while ((((e = (int)(c = ctl)) | (u = (int)(c >>> 32))) &
+                (INT_SIGN|SHORT_SIGN)) == (INT_SIGN|SHORT_SIGN) && e >= 0) {
+            if (e > 0) {                         // release a waiting worker
+                int i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws;
+                if ((ws = workers) == null ||
+                    (i = ~e & SMASK) >= ws.length ||
+                    (w = ws[i]) == null)
+                    break;
+                long nc = (((long)(w.nextWait & E_MASK)) |
+                           ((long)(u + UAC_UNIT) << 32));
+                if (w.eventCount == e &&
+                    UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
+                    w.eventCount = (e + EC_UNIT) & E_MASK;
+                    if (w.parked)
+                        UNSAFE.unpark(w);
+                    break;
+                }
+            }
+            else if (UNSAFE.compareAndSwapLong
+                     (this, ctlOffset, c,
+                      (long)(((u + UTC_UNIT) & UTC_MASK) |
+                             ((u + UAC_UNIT) & UAC_MASK)) << 32)) {
+                addWorker();
+                break;
+            }
+        }
+    }
+
+    /**
+     * Variant of signalWork to help release waiters on rescans.
+     * Tries once to release a waiter if active count < 0.
+     *
+     * @return false if failed due to contention, else true
+     */
+    private boolean tryReleaseWaiter() {
+        long c; int e, i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws;
+        if ((e = (int)(c = ctl)) > 0 &&
+            (int)(c >> AC_SHIFT) < 0 &&
+            (ws = workers) != null &&
+            (i = ~e & SMASK) < ws.length &&
+            (w = ws[i]) != null) {
+            long nc = ((long)(w.nextWait & E_MASK) |
+                       ((c + AC_UNIT) & (AC_MASK|TC_MASK)));
+            if (w.eventCount != e ||
+                !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc))
+                return false;
+            w.eventCount = (e + EC_UNIT) & E_MASK;
+            if (w.parked)
+                UNSAFE.unpark(w);
+        }
+        return true;
+    }
+
+    // Scanning for tasks
+
+    /**
+     * Scans for and, if found, executes one task. Scans start at a
+     * random index of workers array, and randomly select the first
+     * (2*#workers)-1 probes, and then, if all empty, resort to 2
+     * circular sweeps, which is necessary to check quiescence. and
+     * taking a submission only if no stealable tasks were found.  The
+     * steal code inside the loop is a specialized form of
+     * ForkJoinWorkerThread.deqTask, followed bookkeeping to support
+     * helpJoinTask and signal propagation. The code for submission
+     * queues is almost identical. On each steal, the worker completes
+     * not only the task, but also all local tasks that this task may
+     * have generated. On detecting staleness or contention when
+     * trying to take a task, this method returns without finishing
+     * sweep, which allows global state rechecks before retry.
+     *
+     * @param w the worker
+     * @param a the number of active workers
+     * @return true if swept all queues without finding a task
+     */
+    private boolean scan(ForkJoinWorkerThread w, int a) {
+        int g = scanGuard; // mask 0 avoids useless scans if only one active
+        int m = (parallelism == 1 - a && blockedCount == 0) ? 0 : g & SMASK;
+        ForkJoinWorkerThread[] ws = workers;
+        if (ws == null || ws.length <= m)         // staleness check
+            return false;
+        for (int r = w.seed, k = r, j = -(m + m); j <= m + m; ++j) {
+            ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
+            ForkJoinWorkerThread v = ws[k & m];
+            if (v != null && (b = v.queueBase) != v.queueTop &&
+                (q = v.queue) != null && (i = (q.length - 1) & b) >= 0) {
+                long u = (i << ASHIFT) + ABASE;
+                if ((t = q[i]) != null && v.queueBase == b &&
+                    UNSAFE.compareAndSwapObject(q, u, t, null)) {
+                    int d = (v.queueBase = b + 1) - v.queueTop;
+                    v.stealHint = w.poolIndex;
+                    if (d != 0)
+                        signalWork();             // propagate if nonempty
+                    w.execTask(t);
+                }
+                r ^= r << 13; r ^= r >>> 17; w.seed = r ^ (r << 5);
+                return false;                     // store next seed
+            }
+            else if (j < 0) {                     // xorshift
+                r ^= r << 13; r ^= r >>> 17; k = r ^= r << 5;
+            }
+            else
+                ++k;
+        }
+        if (scanGuard != g)                       // staleness check
+            return false;
+        else {                                    // try to take submission
+            ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
+            if ((b = queueBase) != queueTop &&
+                (q = submissionQueue) != null &&
+                (i = (q.length - 1) & b) >= 0) {
+                long u = (i << ASHIFT) + ABASE;
+                if ((t = q[i]) != null && queueBase == b &&
+                    UNSAFE.compareAndSwapObject(q, u, t, null)) {
+                    queueBase = b + 1;
+                    w.execTask(t);
+                }
+                return false;
+            }
+            return true;                         // all queues empty
+        }
+    }
+
+    /**
+     * Tries to enqueue worker w in wait queue and await change in
+     * worker's eventCount.  If the pool is quiescent and there is
+     * more than one worker, possibly terminates worker upon exit.
+     * Otherwise, before blocking, rescans queues to avoid missed
+     * signals.  Upon finding work, releases at least one worker
+     * (which may be the current worker). Rescans restart upon
+     * detected staleness or failure to release due to
+     * contention. Note the unusual conventions about Thread.interrupt
+     * here and elsewhere: Because interrupts are used solely to alert
+     * threads to check termination, which is checked here anyway, we
+     * clear status (using Thread.interrupted) before any call to
+     * park, so that park does not immediately return due to status
+     * being set via some other unrelated call to interrupt in user
+     * code.
+     *
+     * @param w the calling worker
+     * @param c the ctl value on entry
+     * @return true if waited or another thread was released upon enq
+     */
+    private boolean tryAwaitWork(ForkJoinWorkerThread w, long c) {
+        int v = w.eventCount;
+        w.nextWait = (int)c;                      // w's successor record
+        long nc = (long)(v & E_MASK) | ((c - AC_UNIT) & (AC_MASK|TC_MASK));
+        if (ctl != c || !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
+            long d = ctl; // return true if lost to a deq, to force scan
+            return (int)d != (int)c && (d & AC_MASK) >= (c & AC_MASK);
+        }
+        for (int sc = w.stealCount; sc != 0;) {   // accumulate stealCount
+            long s = stealCount;
+            if (UNSAFE.compareAndSwapLong(this, stealCountOffset, s, s + sc))
+                sc = w.stealCount = 0;
+            else if (w.eventCount != v)
+                return true;                      // update next time
+        }
+        if ((!shutdown || !tryTerminate(false)) &&
+            (int)c != 0 && parallelism + (int)(nc >> AC_SHIFT) == 0 &&
+            blockedCount == 0 && quiescerCount == 0)
+            idleAwaitWork(w, nc, c, v);           // quiescent
+        for (boolean rescanned = false;;) {
+            if (w.eventCount != v)
+                return true;
+            if (!rescanned) {
+                int g = scanGuard, m = g & SMASK;
+                ForkJoinWorkerThread[] ws = workers;
+                if (ws != null && m < ws.length) {
+                    rescanned = true;
+                    for (int i = 0; i <= m; ++i) {
+                        ForkJoinWorkerThread u = ws[i];
+                        if (u != null) {
+                            if (u.queueBase != u.queueTop &&
+                                !tryReleaseWaiter())
+                                rescanned = false; // contended
+                            if (w.eventCount != v)
+                                return true;
+                        }
+                    }
+                }
+                if (scanGuard != g ||              // stale
+                    (queueBase != queueTop && !tryReleaseWaiter()))
+                    rescanned = false;
+                if (!rescanned)
+                    Thread.yield();                // reduce contention
+                else
+                    Thread.interrupted();          // clear before park
+            }
+            else {
+                w.parked = true;                   // must recheck
+                if (w.eventCount != v) {
+                    w.parked = false;
+                    return true;
+                }
+                LockSupport.park(this);
+                rescanned = w.parked = false;
+            }
+        }
+    }
+
+    /**
+     * If inactivating worker w has caused pool to become
+     * quiescent, check for pool termination, and wait for event
+     * for up to SHRINK_RATE nanosecs (rescans are unnecessary in
+     * this case because quiescence reflects consensus about lack
+     * of work). On timeout, if ctl has not changed, terminate the
+     * worker. Upon its termination (see deregisterWorker), it may
+     * wake up another worker to possibly repeat this process.
+     *
+     * @param w the calling worker
+     * @param currentCtl the ctl value after enqueuing w
+     * @param prevCtl the ctl value if w terminated
+     * @param v the eventCount w awaits change
+     */
+    private void idleAwaitWork(ForkJoinWorkerThread w, long currentCtl,
+                               long prevCtl, int v) {
+        if (w.eventCount == v) {
+            if (shutdown)
+                tryTerminate(false);
+            ForkJoinTask.helpExpungeStaleExceptions(); // help clean weak refs
+            while (ctl == currentCtl) {
+                long startTime = System.nanoTime();
+                w.parked = true;
+                if (w.eventCount == v)             // must recheck
+                    LockSupport.parkNanos(this, SHRINK_RATE);
+                w.parked = false;
+                if (w.eventCount != v)
+                    break;
+                else if (System.nanoTime() - startTime <
+                         SHRINK_RATE - (SHRINK_RATE / 10)) // timing slop
+                    Thread.interrupted();          // spurious wakeup
+                else if (UNSAFE.compareAndSwapLong(this, ctlOffset,
+                                                   currentCtl, prevCtl)) {
+                    w.terminate = true;            // restore previous
+                    w.eventCount = ((int)currentCtl + EC_UNIT) & E_MASK;
+                    break;
+                }
+            }
+        }
+    }
+
+    // Submissions
+
+    /**
+     * Enqueues the given task in the submissionQueue.  Same idea as
+     * ForkJoinWorkerThread.pushTask except for use of submissionLock.
+     *
+     * @param t the task
+     */
+    private void addSubmission(ForkJoinTask<?> t) {
+        final ReentrantLock lock = this.submissionLock;
+        lock.lock();
+        try {
+            ForkJoinTask<?>[] q; int s, m;
+            if ((q = submissionQueue) != null) {    // ignore if queue removed
+                long u = (((s = queueTop) & (m = q.length-1)) << ASHIFT)+ABASE;
+                UNSAFE.putOrderedObject(q, u, t);
+                queueTop = s + 1;
+                if (s - queueBase == m)
+                    growSubmissionQueue();
+            }
+        } finally {
+            lock.unlock();
+        }
+        signalWork();
+    }
+
+    //  (pollSubmission is defined below with exported methods)
+
+    /**
+     * Creates or doubles submissionQueue array.
+     * Basically identical to ForkJoinWorkerThread version.
+     */
+    private void growSubmissionQueue() {
+        ForkJoinTask<?>[] oldQ = submissionQueue;
+        int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY;
+        if (size > MAXIMUM_QUEUE_CAPACITY)
+            throw new RejectedExecutionException("Queue capacity exceeded");
+        if (size < INITIAL_QUEUE_CAPACITY)
+            size = INITIAL_QUEUE_CAPACITY;
+        ForkJoinTask<?>[] q = submissionQueue = new ForkJoinTask<?>[size];
+        int mask = size - 1;
+        int top = queueTop;
+        int oldMask;
+        if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) {
+            for (int b = queueBase; b != top; ++b) {
+                long u = ((b & oldMask) << ASHIFT) + ABASE;
+                Object x = UNSAFE.getObjectVolatile(oldQ, u);
+                if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null))
+                    UNSAFE.putObjectVolatile
+                        (q, ((b & mask) << ASHIFT) + ABASE, x);
+            }
+        }
+    }
+
+    // Blocking support
+
+    /**
+     * Tries to increment blockedCount, decrement active count
+     * (sometimes implicitly) and possibly release or create a
+     * compensating worker in preparation for blocking. Fails
+     * on contention or termination.
+     *
+     * @return true if the caller can block, else should recheck and retry
+     */
+    private boolean tryPreBlock() {
+        int b = blockedCount;
+        if (UNSAFE.compareAndSwapInt(this, blockedCountOffset, b, b + 1)) {
+            int pc = parallelism;
+            do {
+                ForkJoinWorkerThread[] ws; ForkJoinWorkerThread w;
+                int e, ac, tc, i;
+                long c = ctl;
+                int u = (int)(c >>> 32);
+                if ((e = (int)c) < 0) {
+                                                 // skip -- terminating
+                }
+                else if ((ac = (u >> UAC_SHIFT)) <= 0 && e != 0 &&
+                         (ws = workers) != null &&
+                         (i = ~e & SMASK) < ws.length &&
+                         (w = ws[i]) != null) {
+                    long nc = ((long)(w.nextWait & E_MASK) |
+                               (c & (AC_MASK|TC_MASK)));
+                    if (w.eventCount == e &&
+                        UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
+                        w.eventCount = (e + EC_UNIT) & E_MASK;
+                        if (w.parked)
+                            UNSAFE.unpark(w);
+                        return true;             // release an idle worker
+                    }
+                }
+                else if ((tc = (short)(u >>> UTC_SHIFT)) >= 0 && ac + pc > 1) {
+                    long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK);
+                    if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc))
+                        return true;             // no compensation needed
+                }
+                else if (tc + pc < MAX_ID) {
+                    long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK);
+                    if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
+                        addWorker();
+                        return true;            // create a replacement
+                    }
+                }
+                // try to back out on any failure and let caller retry
+            } while (!UNSAFE.compareAndSwapInt(this, blockedCountOffset,
+                                               b = blockedCount, b - 1));
+        }
+        return false;
+    }
+
+    /**
+     * Decrements blockedCount and increments active count.
+     */
+    private void postBlock() {
+        long c;
+        do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset,  // no mask
+                                                c = ctl, c + AC_UNIT));
+        int b;
+        do {} while (!UNSAFE.compareAndSwapInt(this, blockedCountOffset,
+                                               b = blockedCount, b - 1));
+    }
+
+    /**
+     * Possibly blocks waiting for the given task to complete, or
+     * cancels the task if terminating.  Fails to wait if contended.
+     *
+     * @param joinMe the task
+     */
+    final void tryAwaitJoin(ForkJoinTask<?> joinMe) {
+        Thread.interrupted(); // clear interrupts before checking termination
+        if (joinMe.status >= 0) {
+            if (tryPreBlock()) {
+                joinMe.tryAwaitDone(0L);
+                postBlock();
+            }
+            else if ((ctl & STOP_BIT) != 0L)
+                joinMe.cancelIgnoringExceptions();
+        }
+    }
+
+    /**
+     * Possibly blocks the given worker waiting for joinMe to
+     * complete or timeout.
+     *
+     * @param joinMe the task
+     * @param nanos the wait time for underlying Object.wait
+     */
+    final void timedAwaitJoin(ForkJoinTask<?> joinMe, long nanos) {
+        while (joinMe.status >= 0) {
+            Thread.interrupted();
+            if ((ctl & STOP_BIT) != 0L) {
+                joinMe.cancelIgnoringExceptions();
+                break;
+            }
+            if (tryPreBlock()) {
+                long last = System.nanoTime();
+                while (joinMe.status >= 0) {
+                    long millis = TimeUnit.NANOSECONDS.toMillis(nanos);
+                    if (millis <= 0)
+                        break;
+                    joinMe.tryAwaitDone(millis);
+                    if (joinMe.status < 0)
+                        break;
+                    if ((ctl & STOP_BIT) != 0L) {
+                        joinMe.cancelIgnoringExceptions();
+                        break;
+                    }
+                    long now = System.nanoTime();
+                    nanos -= now - last;
+                    last = now;
+                }
+                postBlock();
+                break;
+            }
+        }
+    }
+
+    /**
+     * If necessary, compensates for blocker, and blocks.
+     */
+    private void awaitBlocker(ManagedBlocker blocker)
+        throws InterruptedException {
+        while (!blocker.isReleasable()) {
+            if (tryPreBlock()) {
+                try {
+                    do {} while (!blocker.isReleasable() && !blocker.block());
+                } finally {
+                    postBlock();
+                }
+                break;
+            }
+        }
+    }
+
+    // Creating, registering and deregistring workers
+
+    /**
+     * Tries to create and start a worker; minimally rolls back counts
+     * on failure.
+     */
+    private void addWorker() {
+        Throwable ex = null;
+        ForkJoinWorkerThread t = null;
+        try {
+            t = factory.newThread(this);
+        } catch (Throwable e) {
+            ex = e;
+        }
+        if (t == null) {  // null or exceptional factory return
+            long c;       // adjust counts
+            do {} while (!UNSAFE.compareAndSwapLong
+                         (this, ctlOffset, c = ctl,
+                          (((c - AC_UNIT) & AC_MASK) |
+                           ((c - TC_UNIT) & TC_MASK) |
+                           (c & ~(AC_MASK|TC_MASK)))));
+            // Propagate exception if originating from an external caller
+            if (!tryTerminate(false) && ex != null &&
+                !(Thread.currentThread() instanceof ForkJoinWorkerThread))
+                SneakyThrow.sneakyThrow(ex); // android-changed
+        }
+        else
+            t.start();
+    }
+
+    /**
+     * Callback from ForkJoinWorkerThread constructor to assign a
+     * public name
+     */
+    final String nextWorkerName() {
+        for (int n;;) {
+            if (UNSAFE.compareAndSwapInt(this, nextWorkerNumberOffset,
+                                         n = nextWorkerNumber, ++n))
+                return workerNamePrefix + n;
+        }
+    }
+
+    /**
+     * Callback from ForkJoinWorkerThread constructor to
+     * determine its poolIndex and record in workers array.
+     *
+     * @param w the worker
+     * @return the worker's pool index
+     */
+    final int registerWorker(ForkJoinWorkerThread w) {
+        /*
+         * In the typical case, a new worker acquires the lock, uses
+         * next available index and returns quickly.  Since we should
+         * not block callers (ultimately from signalWork or
+         * tryPreBlock) waiting for the lock needed to do this, we
+         * instead help release other workers while waiting for the
+         * lock.
+         */
+        for (int g;;) {
+            ForkJoinWorkerThread[] ws;
+            if (((g = scanGuard) & SG_UNIT) == 0 &&
+                UNSAFE.compareAndSwapInt(this, scanGuardOffset,
+                                         g, g | SG_UNIT)) {
+                int k = nextWorkerIndex;
+                try {
+                    if ((ws = workers) != null) { // ignore on shutdown
+                        int n = ws.length;
+                        if (k < 0 || k >= n || ws[k] != null) {
+                            for (k = 0; k < n && ws[k] != null; ++k)
+                                ;
+                            if (k == n)
+                                ws = workers = Arrays.copyOf(ws, n << 1);
+                        }
+                        ws[k] = w;
+                        nextWorkerIndex = k + 1;
+                        int m = g & SMASK;
+                        g = (k > m) ? ((m << 1) + 1) & SMASK : g + (SG_UNIT<<1);
+                    }
+                } finally {
+                    scanGuard = g;
+                }
+                return k;
+            }
+            else if ((ws = workers) != null) { // help release others
+                for (ForkJoinWorkerThread u : ws) {
+                    if (u != null && u.queueBase != u.queueTop) {
+                        if (tryReleaseWaiter())
+                            break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Final callback from terminating worker.  Removes record of
+     * worker from array, and adjusts counts. If pool is shutting
+     * down, tries to complete termination.
+     *
+     * @param w the worker
+     */
+    final void deregisterWorker(ForkJoinWorkerThread w, Throwable ex) {
+        int idx = w.poolIndex;
+        int sc = w.stealCount;
+        int steps = 0;
+        // Remove from array, adjust worker counts and collect steal count.
+        // We can intermix failed removes or adjusts with steal updates
+        do {
+            long s, c;
+            int g;
+            if (steps == 0 && ((g = scanGuard) & SG_UNIT) == 0 &&
+                UNSAFE.compareAndSwapInt(this, scanGuardOffset,
+                                         g, g |= SG_UNIT)) {
+                ForkJoinWorkerThread[] ws = workers;
+                if (ws != null && idx >= 0 &&
+                    idx < ws.length && ws[idx] == w)
+                    ws[idx] = null;    // verify
+                nextWorkerIndex = idx;
+                scanGuard = g + SG_UNIT;
+                steps = 1;
+            }
+            if (steps == 1 &&
+                UNSAFE.compareAndSwapLong(this, ctlOffset, c = ctl,
+                                          (((c - AC_UNIT) & AC_MASK) |
+                                           ((c - TC_UNIT) & TC_MASK) |
+                                           (c & ~(AC_MASK|TC_MASK)))))
+                steps = 2;
+            if (sc != 0 &&
+                UNSAFE.compareAndSwapLong(this, stealCountOffset,
+                                          s = stealCount, s + sc))
+                sc = 0;
+        } while (steps != 2 || sc != 0);
+        if (!tryTerminate(false)) {
+            if (ex != null)   // possibly replace if died abnormally
+                signalWork();
+            else
+                tryReleaseWaiter();
+        }
+    }
+
+    // Shutdown and termination
+
+    /**
+     * Possibly initiates and/or completes termination.
+     *
+     * @param now if true, unconditionally terminate, else only
+     * if shutdown and empty queue and no active workers
+     * @return true if now terminating or terminated
+     */
+    private boolean tryTerminate(boolean now) {
+        long c;
+        while (((c = ctl) & STOP_BIT) == 0) {
+            if (!now) {
+                if ((int)(c >> AC_SHIFT) != -parallelism)
+                    return false;
+                if (!shutdown || blockedCount != 0 || quiescerCount != 0 ||
+                    queueBase != queueTop) {
+                    if (ctl == c) // staleness check
+                        return false;
+                    continue;
+                }
+            }
+            if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, c | STOP_BIT))
+                startTerminating();
+        }
+        if ((short)(c >>> TC_SHIFT) == -parallelism) { // signal when 0 workers
+            final ReentrantLock lock = this.submissionLock;
+            lock.lock();
+            try {
+                termination.signalAll();
+            } finally {
+                lock.unlock();
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Runs up to three passes through workers: (0) Setting
+     * termination status for each worker, followed by wakeups up to
+     * queued workers; (1) helping cancel tasks; (2) interrupting
+     * lagging threads (likely in external tasks, but possibly also
+     * blocked in joins).  Each pass repeats previous steps because of
+     * potential lagging thread creation.
+     */
+    private void startTerminating() {
+        cancelSubmissions();
+        for (int pass = 0; pass < 3; ++pass) {
+            ForkJoinWorkerThread[] ws = workers;
+            if (ws != null) {
+                for (ForkJoinWorkerThread w : ws) {
+                    if (w != null) {
+                        w.terminate = true;
+                        if (pass > 0) {
+                            w.cancelTasks();
+                            if (pass > 1 && !w.isInterrupted()) {
+                                try {
+                                    w.interrupt();
+                                } catch (SecurityException ignore) {
+                                }
+                            }
+                        }
+                    }
+                }
+                terminateWaiters();
+            }
+        }
+    }
+
+    /**
+     * Polls and cancels all submissions. Called only during termination.
+     */
+    private void cancelSubmissions() {
+        while (queueBase != queueTop) {
+            ForkJoinTask<?> task = pollSubmission();
+            if (task != null) {
+                try {
+                    task.cancel(false);
+                } catch (Throwable ignore) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Tries to set the termination status of waiting workers, and
+     * then wakes them up (after which they will terminate).
+     */
+    private void terminateWaiters() {
+        ForkJoinWorkerThread[] ws = workers;
+        if (ws != null) {
+            ForkJoinWorkerThread w; long c; int i, e;
+            int n = ws.length;
+            while ((i = ~(e = (int)(c = ctl)) & SMASK) < n &&
+                   (w = ws[i]) != null && w.eventCount == (e & E_MASK)) {
+                if (UNSAFE.compareAndSwapLong(this, ctlOffset, c,
+                                              (long)(w.nextWait & E_MASK) |
+                                              ((c + AC_UNIT) & AC_MASK) |
+                                              (c & (TC_MASK|STOP_BIT)))) {
+                    w.terminate = true;
+                    w.eventCount = e + EC_UNIT;
+                    if (w.parked)
+                        UNSAFE.unpark(w);
+                }
+            }
+        }
+    }
+
+    // misc ForkJoinWorkerThread support
+
+    /**
+     * Increments or decrements quiescerCount. Needed only to prevent
+     * triggering shutdown if a worker is transiently inactive while
+     * checking quiescence.
+     *
+     * @param delta 1 for increment, -1 for decrement
+     */
+    final void addQuiescerCount(int delta) {
+        int c;
+        do {} while (!UNSAFE.compareAndSwapInt(this, quiescerCountOffset,
+                                               c = quiescerCount, c + delta));
+    }
+
+    /**
+     * Directly increments or decrements active count without queuing.
+     * This method is used to transiently assert inactivation while
+     * checking quiescence.
+     *
+     * @param delta 1 for increment, -1 for decrement
+     */
+    final void addActiveCount(int delta) {
+        long d = (long)delta << AC_SHIFT;
+        long c;
+        do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset,
+                                                c = ctl, c + d));
+    }
+
+    /**
+     * Returns the approximate (non-atomic) number of idle threads per
+     * active thread.
+     */
+    final int idlePerActive() {
+        // Approximate at powers of two for small values, saturate past 4
+        int p = parallelism;
+        int a = p + (int)(ctl >> AC_SHIFT);
+        return (a > (p >>>= 1) ? 0 :
+                a > (p >>>= 1) ? 1 :
+                a > (p >>>= 1) ? 2 :
+                a > (p >>>= 1) ? 4 :
+                8);
+    }
+
+    // Exported methods
+
+    // Constructors
+
+    /**
+     * Creates a {@code ForkJoinPool} with parallelism equal to {@link
+     * java.lang.Runtime#availableProcessors}, using the {@linkplain
+     * #defaultForkJoinWorkerThreadFactory default thread factory},
+     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     */
+    public ForkJoinPool() {
+        this(Runtime.getRuntime().availableProcessors(),
+             defaultForkJoinWorkerThreadFactory, null, false);
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the indicated parallelism
+     * level, the {@linkplain
+     * #defaultForkJoinWorkerThreadFactory default thread factory},
+     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     *
+     * @param parallelism the parallelism level
+     * @throws IllegalArgumentException if parallelism less than or
+     *         equal to zero, or greater than implementation limit
+     */
+    public ForkJoinPool(int parallelism) {
+        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the given parameters.
+     *
+     * @param parallelism the parallelism level. For default value,
+     * use {@link java.lang.Runtime#availableProcessors}.
+     * @param factory the factory for creating new threads. For default value,
+     * use {@link #defaultForkJoinWorkerThreadFactory}.
+     * @param handler the handler for internal worker threads that
+     * terminate due to unrecoverable errors encountered while executing
+     * tasks. For default value, use {@code null}.
+     * @param asyncMode if true,
+     * establishes local first-in-first-out scheduling mode for forked
+     * tasks that are never joined. This mode may be more appropriate
+     * than default locally stack-based mode in applications in which
+     * worker threads only process event-style asynchronous tasks.
+     * For default value, use {@code false}.
+     * @throws IllegalArgumentException if parallelism less than or
+     *         equal to zero, or greater than implementation limit
+     * @throws NullPointerException if the factory is null
+     */
+    public ForkJoinPool(int parallelism,
+                        ForkJoinWorkerThreadFactory factory,
+                        Thread.UncaughtExceptionHandler handler,
+                        boolean asyncMode) {
+        checkPermission();
+        if (factory == null)
+            throw new NullPointerException();
+        if (parallelism <= 0 || parallelism > MAX_ID)
+            throw new IllegalArgumentException();
+        this.parallelism = parallelism;
+        this.factory = factory;
+        this.ueh = handler;
+        this.locallyFifo = asyncMode;
+        long np = (long)(-parallelism); // offset ctl counts
+        this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
+        this.submissionQueue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
+        // initialize workers array with room for 2*parallelism if possible
+        int n = parallelism << 1;
+        if (n >= MAX_ID)
+            n = MAX_ID;
+        else { // See Hackers Delight, sec 3.2, where n < (1 << 16)
+            n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8;
+        }
+        workers = new ForkJoinWorkerThread[n + 1];
+        this.submissionLock = new ReentrantLock();
+        this.termination = submissionLock.newCondition();
+        StringBuilder sb = new StringBuilder("ForkJoinPool-");
+        sb.append(poolNumberGenerator.incrementAndGet());
+        sb.append("-worker-");
+        this.workerNamePrefix = sb.toString();
+    }
+
+    // Execution methods
+
+    /**
+     * Performs the given task, returning its result upon completion.
+     * If the computation encounters an unchecked Exception or Error,
+     * it is rethrown as the outcome of this invocation.  Rethrown
+     * exceptions behave in the same way as regular exceptions, but,
+     * when possible, contain stack traces (as displayed for example
+     * using {@code ex.printStackTrace()}) of both the current thread
+     * as well as the thread actually encountering the exception;
+     * minimally only the latter.
+     *
+     * @param task the task
+     * @return the task's result
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> T invoke(ForkJoinTask<T> task) {
+        Thread t = Thread.currentThread();
+        if (task == null)
+            throw new NullPointerException();
+        if (shutdown)
+            throw new RejectedExecutionException();
+        if ((t instanceof ForkJoinWorkerThread) &&
+            ((ForkJoinWorkerThread)t).pool == this)
+            return task.invoke();  // bypass submit if in same pool
+        else {
+            addSubmission(task);
+            return task.join();
+        }
+    }
+
+    /**
+     * Unless terminating, forks task if within an ongoing FJ
+     * computation in the current pool, else submits as external task.
+     */
+    private <T> void forkOrSubmit(ForkJoinTask<T> task) {
+        ForkJoinWorkerThread w;
+        Thread t = Thread.currentThread();
+        if (shutdown)
+            throw new RejectedExecutionException();
+        if ((t instanceof ForkJoinWorkerThread) &&
+            (w = (ForkJoinWorkerThread)t).pool == this)
+            w.pushTask(task);
+        else
+            addSubmission(task);
+    }
+
+    /**
+     * Arranges for (asynchronous) execution of the given task.
+     *
+     * @param task the task
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public void execute(ForkJoinTask<?> task) {
+        if (task == null)
+            throw new NullPointerException();
+        forkOrSubmit(task);
+    }
+
+    // AbstractExecutorService methods
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public void execute(Runnable task) {
+        if (task == null)
+            throw new NullPointerException();
+        ForkJoinTask<?> job;
+        if (task instanceof ForkJoinTask<?>) // avoid re-wrap
+            job = (ForkJoinTask<?>) task;
+        else
+            job = ForkJoinTask.adapt(task, null);
+        forkOrSubmit(job);
+    }
+
+    /**
+     * Submits a ForkJoinTask for execution.
+     *
+     * @param task the task to submit
+     * @return the task
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
+        if (task == null)
+            throw new NullPointerException();
+        forkOrSubmit(task);
+        return task;
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> ForkJoinTask<T> submit(Callable<T> task) {
+        if (task == null)
+            throw new NullPointerException();
+        ForkJoinTask<T> job = ForkJoinTask.adapt(task);
+        forkOrSubmit(job);
+        return job;
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> ForkJoinTask<T> submit(Runnable task, T result) {
+        if (task == null)
+            throw new NullPointerException();
+        ForkJoinTask<T> job = ForkJoinTask.adapt(task, result);
+        forkOrSubmit(job);
+        return job;
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public ForkJoinTask<?> submit(Runnable task) {
+        if (task == null)
+            throw new NullPointerException();
+        ForkJoinTask<?> job;
+        if (task instanceof ForkJoinTask<?>) // avoid re-wrap
+            job = (ForkJoinTask<?>) task;
+        else
+            job = ForkJoinTask.adapt(task, null);
+        forkOrSubmit(job);
+        return job;
+    }
+
+    /**
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws RejectedExecutionException {@inheritDoc}
+     */
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
+        ArrayList<ForkJoinTask<T>> forkJoinTasks =
+            new ArrayList<ForkJoinTask<T>>(tasks.size());
+        for (Callable<T> task : tasks)
+            forkJoinTasks.add(ForkJoinTask.adapt(task));
+        invoke(new InvokeAll<T>(forkJoinTasks));
+
+        @SuppressWarnings({"unchecked", "rawtypes"})
+            List<Future<T>> futures = (List<Future<T>>) (List) forkJoinTasks;
+        return futures;
+    }
+
+    static final class InvokeAll<T> extends RecursiveAction {
+        final ArrayList<ForkJoinTask<T>> tasks;
+        InvokeAll(ArrayList<ForkJoinTask<T>> tasks) { this.tasks = tasks; }
+        public void compute() {
+            try { invokeAll(tasks); }
+            catch (Exception ignore) {}
+        }
+        private static final long serialVersionUID = -7914297376763021607L;
+    }
+
+    /**
+     * Returns the factory used for constructing new workers.
+     *
+     * @return the factory used for constructing new workers
+     */
+    public ForkJoinWorkerThreadFactory getFactory() {
+        return factory;
+    }
+
+    /**
+     * Returns the handler for internal worker threads that terminate
+     * due to unrecoverable errors encountered while executing tasks.
+     *
+     * @return the handler, or {@code null} if none
+     */
+    public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
+        return ueh;
+    }
+
+    /**
+     * Returns the targeted parallelism level of this pool.
+     *
+     * @return the targeted parallelism level of this pool
+     */
+    public int getParallelism() {
+        return parallelism;
+    }
+
+    /**
+     * Returns the number of worker threads that have started but not
+     * yet terminated.  The result returned by this method may differ
+     * from {@link #getParallelism} when threads are created to
+     * maintain parallelism when others are cooperatively blocked.
+     *
+     * @return the number of worker threads
+     */
+    public int getPoolSize() {
+        return parallelism + (short)(ctl >>> TC_SHIFT);
+    }
+
+    /**
+     * Returns {@code true} if this pool uses local first-in-first-out
+     * scheduling mode for forked tasks that are never joined.
+     *
+     * @return {@code true} if this pool uses async mode
+     */
+    public boolean getAsyncMode() {
+        return locallyFifo;
+    }
+
+    /**
+     * Returns an estimate of the number of worker threads that are
+     * not blocked waiting to join tasks or for other managed
+     * synchronization. This method may overestimate the
+     * number of running threads.
+     *
+     * @return the number of worker threads
+     */
+    public int getRunningThreadCount() {
+        int r = parallelism + (int)(ctl >> AC_SHIFT);
+        return (r <= 0) ? 0 : r; // suppress momentarily negative values
+    }
+
+    /**
+     * Returns an estimate of the number of threads that are currently
+     * stealing or executing tasks. This method may overestimate the
+     * number of active threads.
+     *
+     * @return the number of active threads
+     */
+    public int getActiveThreadCount() {
+        int r = parallelism + (int)(ctl >> AC_SHIFT) + blockedCount;
+        return (r <= 0) ? 0 : r; // suppress momentarily negative values
+    }
+
+    /**
+     * Returns {@code true} if all worker threads are currently idle.
+     * An idle worker is one that cannot obtain a task to execute
+     * because none are available to steal from other threads, and
+     * there are no pending submissions to the pool. This method is
+     * conservative; it might not return {@code true} immediately upon
+     * idleness of all threads, but will eventually become true if
+     * threads remain inactive.
+     *
+     * @return {@code true} if all threads are currently idle
+     */
+    public boolean isQuiescent() {
+        return parallelism + (int)(ctl >> AC_SHIFT) + blockedCount == 0;
+    }
+
+    /**
+     * Returns an estimate of the total number of tasks stolen from
+     * one thread's work queue by another. The reported value
+     * underestimates the actual total number of steals when the pool
+     * is not quiescent. This value may be useful for monitoring and
+     * tuning fork/join programs: in general, steal counts should be
+     * high enough to keep threads busy, but low enough to avoid
+     * overhead and contention across threads.
+     *
+     * @return the number of steals
+     */
+    public long getStealCount() {
+        return stealCount;
+    }
+
+    /**
+     * Returns an estimate of the total number of tasks currently held
+     * in queues by worker threads (but not including tasks submitted
+     * to the pool that have not begun executing). This value is only
+     * an approximation, obtained by iterating across all threads in
+     * the pool. This method may be useful for tuning task
+     * granularities.
+     *
+     * @return the number of queued tasks
+     */
+    public long getQueuedTaskCount() {
+        long count = 0;
+        ForkJoinWorkerThread[] ws;
+        if ((short)(ctl >>> TC_SHIFT) > -parallelism &&
+            (ws = workers) != null) {
+            for (ForkJoinWorkerThread w : ws)
+                if (w != null)
+                    count -= w.queueBase - w.queueTop; // must read base first
+        }
+        return count;
+    }
+
+    /**
+     * Returns an estimate of the number of tasks submitted to this
+     * pool that have not yet begun executing.  This method may take
+     * time proportional to the number of submissions.
+     *
+     * @return the number of queued submissions
+     */
+    public int getQueuedSubmissionCount() {
+        return -queueBase + queueTop;
+    }
+
+    /**
+     * Returns {@code true} if there are any tasks submitted to this
+     * pool that have not yet begun executing.
+     *
+     * @return {@code true} if there are any queued submissions
+     */
+    public boolean hasQueuedSubmissions() {
+        return queueBase != queueTop;
+    }
+
+    /**
+     * Removes and returns the next unexecuted submission if one is
+     * available.  This method may be useful in extensions to this
+     * class that re-assign work in systems with multiple pools.
+     *
+     * @return the next submission, or {@code null} if none
+     */
+    protected ForkJoinTask<?> pollSubmission() {
+        ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
+        while ((b = queueBase) != queueTop &&
+               (q = submissionQueue) != null &&
+               (i = (q.length - 1) & b) >= 0) {
+            long u = (i << ASHIFT) + ABASE;
+            if ((t = q[i]) != null &&
+                queueBase == b &&
+                UNSAFE.compareAndSwapObject(q, u, t, null)) {
+                queueBase = b + 1;
+                return t;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes all available unexecuted submitted and forked tasks
+     * from scheduling queues and adds them to the given collection,
+     * without altering their execution status. These may include
+     * artificially generated or wrapped tasks. This method is
+     * designed to be invoked only when the pool is known to be
+     * quiescent. Invocations at other times may not remove all
+     * tasks. A failure encountered while attempting to add elements
+     * to collection {@code c} may result in elements being in
+     * neither, either or both collections when the associated
+     * exception is thrown.  The behavior of this operation is
+     * undefined if the specified collection is modified while the
+     * operation is in progress.
+     *
+     * @param c the collection to transfer elements into
+     * @return the number of elements transferred
+     */
+    protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
+        int count = 0;
+        while (queueBase != queueTop) {
+            ForkJoinTask<?> t = pollSubmission();
+            if (t != null) {
+                c.add(t);
+                ++count;
+            }
+        }
+        ForkJoinWorkerThread[] ws;
+        if ((short)(ctl >>> TC_SHIFT) > -parallelism &&
+            (ws = workers) != null) {
+            for (ForkJoinWorkerThread w : ws)
+                if (w != null)
+                    count += w.drainTasksTo(c);
+        }
+        return count;
+    }
+
+    /**
+     * Returns a string identifying this pool, as well as its state,
+     * including indications of run state, parallelism level, and
+     * worker and task counts.
+     *
+     * @return a string identifying this pool, as well as its state
+     */
+    public String toString() {
+        long st = getStealCount();
+        long qt = getQueuedTaskCount();
+        long qs = getQueuedSubmissionCount();
+        int pc = parallelism;
+        long c = ctl;
+        int tc = pc + (short)(c >>> TC_SHIFT);
+        int rc = pc + (int)(c >> AC_SHIFT);
+        if (rc < 0) // ignore transient negative
+            rc = 0;
+        int ac = rc + blockedCount;
+        String level;
+        if ((c & STOP_BIT) != 0)
+            level = (tc == 0) ? "Terminated" : "Terminating";
+        else
+            level = shutdown ? "Shutting down" : "Running";
+        return super.toString() +
+            "[" + level +
+            ", parallelism = " + pc +
+            ", size = " + tc +
+            ", active = " + ac +
+            ", running = " + rc +
+            ", steals = " + st +
+            ", tasks = " + qt +
+            ", submissions = " + qs +
+            "]";
+    }
+
+    /**
+     * Initiates an orderly shutdown in which previously submitted
+     * tasks are executed, but no new tasks will be accepted.
+     * Invocation has no additional effect if already shut down.
+     * Tasks that are in the process of being submitted concurrently
+     * during the course of this method may or may not be rejected.
+     */
+    public void shutdown() {
+        checkPermission();
+        shutdown = true;
+        tryTerminate(false);
+    }
+
+    /**
+     * Attempts to cancel and/or stop all tasks, and reject all
+     * subsequently submitted tasks.  Tasks that are in the process of
+     * being submitted or executed concurrently during the course of
+     * this method may or may not be rejected. This method cancels
+     * both existing and unexecuted tasks, in order to permit
+     * termination in the presence of task dependencies. So the method
+     * always returns an empty list (unlike the case for some other
+     * Executors).
+     *
+     * @return an empty list
+     */
+    public List<Runnable> shutdownNow() {
+        checkPermission();
+        shutdown = true;
+        tryTerminate(true);
+        return Collections.emptyList();
+    }
+
+    /**
+     * Returns {@code true} if all tasks have completed following shut down.
+     *
+     * @return {@code true} if all tasks have completed following shut down
+     */
+    public boolean isTerminated() {
+        long c = ctl;
+        return ((c & STOP_BIT) != 0L &&
+                (short)(c >>> TC_SHIFT) == -parallelism);
+    }
+
+    /**
+     * Returns {@code true} if the process of termination has
+     * commenced but not yet completed.  This method may be useful for
+     * debugging. A return of {@code true} reported a sufficient
+     * period after shutdown may indicate that submitted tasks have
+     * ignored or suppressed interruption, or are waiting for IO,
+     * causing this executor not to properly terminate. (See the
+     * advisory notes for class {@link ForkJoinTask} stating that
+     * tasks should not normally entail blocking operations.  But if
+     * they do, they must abort them on interrupt.)
+     *
+     * @return {@code true} if terminating but not yet terminated
+     */
+    public boolean isTerminating() {
+        long c = ctl;
+        return ((c & STOP_BIT) != 0L &&
+                (short)(c >>> TC_SHIFT) != -parallelism);
+    }
+
+    /**
+     * Returns true if terminating or terminated. Used by ForkJoinWorkerThread.
+     */
+    final boolean isAtLeastTerminating() {
+        return (ctl & STOP_BIT) != 0L;
+    }
+
+    /**
+     * Returns {@code true} if this pool has been shut down.
+     *
+     * @return {@code true} if this pool has been shut down
+     */
+    public boolean isShutdown() {
+        return shutdown;
+    }
+
+    /**
+     * Blocks until all tasks have completed execution after a shutdown
+     * request, or the timeout occurs, or the current thread is
+     * interrupted, whichever happens first.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if this executor terminated and
+     *         {@code false} if the timeout elapsed before termination
+     * @throws InterruptedException if interrupted while waiting
+     */
+    public boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.submissionLock;
+        lock.lock();
+        try {
+            for (;;) {
+                if (isTerminated())
+                    return true;
+                if (nanos <= 0)
+                    return false;
+                nanos = termination.awaitNanos(nanos);
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Interface for extending managed parallelism for tasks running
+     * in {@link ForkJoinPool}s.
+     *
+     * <p>A {@code ManagedBlocker} provides two methods.  Method
+     * {@code isReleasable} must return {@code true} if blocking is
+     * not necessary. Method {@code block} blocks the current thread
+     * if necessary (perhaps internally invoking {@code isReleasable}
+     * before actually blocking). These actions are performed by any
+     * thread invoking {@link ForkJoinPool#managedBlock}.  The
+     * unusual methods in this API accommodate synchronizers that may,
+     * but don't usually, block for long periods. Similarly, they
+     * allow more efficient internal handling of cases in which
+     * additional workers may be, but usually are not, needed to
+     * ensure sufficient parallelism.  Toward this end,
+     * implementations of method {@code isReleasable} must be amenable
+     * to repeated invocation.
+     *
+     * <p>For example, here is a ManagedBlocker based on a
+     * ReentrantLock:
+     *  <pre> {@code
+     * class ManagedLocker implements ManagedBlocker {
+     *   final ReentrantLock lock;
+     *   boolean hasLock = false;
+     *   ManagedLocker(ReentrantLock lock) { this.lock = lock; }
+     *   public boolean block() {
+     *     if (!hasLock)
+     *       lock.lock();
+     *     return true;
+     *   }
+     *   public boolean isReleasable() {
+     *     return hasLock || (hasLock = lock.tryLock());
+     *   }
+     * }}</pre>
+     *
+     * <p>Here is a class that possibly blocks waiting for an
+     * item on a given queue:
+     *  <pre> {@code
+     * class QueueTaker<E> implements ManagedBlocker {
+     *   final BlockingQueue<E> queue;
+     *   volatile E item = null;
+     *   QueueTaker(BlockingQueue<E> q) { this.queue = q; }
+     *   public boolean block() throws InterruptedException {
+     *     if (item == null)
+     *       item = queue.take();
+     *     return true;
+     *   }
+     *   public boolean isReleasable() {
+     *     return item != null || (item = queue.poll()) != null;
+     *   }
+     *   public E getItem() { // call after pool.managedBlock completes
+     *     return item;
+     *   }
+     * }}</pre>
+     */
+    public static interface ManagedBlocker {
+        /**
+         * Possibly blocks the current thread, for example waiting for
+         * a lock or condition.
+         *
+         * @return {@code true} if no additional blocking is necessary
+         * (i.e., if isReleasable would return true)
+         * @throws InterruptedException if interrupted while waiting
+         * (the method is not required to do so, but is allowed to)
+         */
+        boolean block() throws InterruptedException;
+
+        /**
+         * Returns {@code true} if blocking is unnecessary.
+         */
+        boolean isReleasable();
+    }
+
+    /**
+     * Blocks in accord with the given blocker.  If the current thread
+     * is a {@link ForkJoinWorkerThread}, this method possibly
+     * arranges for a spare thread to be activated if necessary to
+     * ensure sufficient parallelism while the current thread is blocked.
+     *
+     * <p>If the caller is not a {@link ForkJoinTask}, this method is
+     * behaviorally equivalent to
+     *  <pre> {@code
+     * while (!blocker.isReleasable())
+     *   if (blocker.block())
+     *     return;
+     * }</pre>
+     *
+     * If the caller is a {@code ForkJoinTask}, then the pool may
+     * first be expanded to ensure parallelism, and later adjusted.
+     *
+     * @param blocker the blocker
+     * @throws InterruptedException if blocker.block did so
+     */
+    public static void managedBlock(ManagedBlocker blocker)
+        throws InterruptedException {
+        Thread t = Thread.currentThread();
+        if (t instanceof ForkJoinWorkerThread) {
+            ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
+            w.pool.awaitBlocker(blocker);
+        }
+        else {
+            do {} while (!blocker.isReleasable() && !blocker.block());
+        }
+    }
+
+    // AbstractExecutorService overrides.  These rely on undocumented
+    // fact that ForkJoinTask.adapt returns ForkJoinTasks that also
+    // implement RunnableFuture.
+
+    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
+        return (RunnableFuture<T>) ForkJoinTask.adapt(runnable, value);
+    }
+
+    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
+        return (RunnableFuture<T>) ForkJoinTask.adapt(callable);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long ctlOffset;
+    private static final long stealCountOffset;
+    private static final long blockedCountOffset;
+    private static final long quiescerCountOffset;
+    private static final long scanGuardOffset;
+    private static final long nextWorkerNumberOffset;
+    private static final long ABASE;
+    private static final int ASHIFT;
+
+    static {
+        poolNumberGenerator = new AtomicInteger();
+        workerSeedGenerator = new Random();
+        modifyThreadPermission = new RuntimePermission("modifyThread");
+        defaultForkJoinWorkerThreadFactory =
+            new DefaultForkJoinWorkerThreadFactory();
+        try {
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = ForkJoinPool.class;
+            ctlOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("ctl"));
+            stealCountOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("stealCount"));
+            blockedCountOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("blockedCount"));
+            quiescerCountOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("quiescerCount"));
+            scanGuardOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("scanGuard"));
+            nextWorkerNumberOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("nextWorkerNumber"));
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+        Class<?> a = ForkJoinTask[].class;
+        ABASE = UNSAFE.arrayBaseOffset(a);
+        int s = UNSAFE.arrayIndexScale(a);
+        if ((s & (s-1)) != 0)
+            throw new Error("data type scale not a power of two");
+        ASHIFT = 31 - Integer.numberOfLeadingZeros(s);
+    }
+
+}
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
new file mode 100644
index 0000000..86a29d7
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
@@ -0,0 +1,1357 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantLock;
+import java.lang.reflect.Constructor;
+import libcore.util.SneakyThrow;
+
+/**
+ * Abstract base class for tasks that run within a {@link ForkJoinPool}.
+ * A {@code ForkJoinTask} is a thread-like entity that is much
+ * lighter weight than a normal thread.  Huge numbers of tasks and
+ * subtasks may be hosted by a small number of actual threads in a
+ * ForkJoinPool, at the price of some usage limitations.
+ *
+ * <p>A "main" {@code ForkJoinTask} begins execution when submitted
+ * to a {@link ForkJoinPool}.  Once started, it will usually in turn
+ * start other subtasks.  As indicated by the name of this class,
+ * many programs using {@code ForkJoinTask} employ only methods
+ * {@link #fork} and {@link #join}, or derivatives such as {@link
+ * #invokeAll(ForkJoinTask...) invokeAll}.  However, this class also
+ * provides a number of other methods that can come into play in
+ * advanced usages, as well as extension mechanics that allow
+ * support of new forms of fork/join processing.
+ *
+ * <p>A {@code ForkJoinTask} is a lightweight form of {@link Future}.
+ * The efficiency of {@code ForkJoinTask}s stems from a set of
+ * restrictions (that are only partially statically enforceable)
+ * reflecting their intended use as computational tasks calculating
+ * pure functions or operating on purely isolated objects.  The
+ * primary coordination mechanisms are {@link #fork}, that arranges
+ * asynchronous execution, and {@link #join}, that doesn't proceed
+ * until the task's result has been computed.  Computations should
+ * avoid {@code synchronized} methods or blocks, and should minimize
+ * other blocking synchronization apart from joining other tasks or
+ * using synchronizers such as Phasers that are advertised to
+ * cooperate with fork/join scheduling. Tasks should also not perform
+ * blocking IO, and should ideally access variables that are
+ * completely independent of those accessed by other running
+ * tasks. Minor breaches of these restrictions, for example using
+ * shared output streams, may be tolerable in practice, but frequent
+ * use may result in poor performance, and the potential to
+ * indefinitely stall if the number of threads not waiting for IO or
+ * other external synchronization becomes exhausted. This usage
+ * restriction is in part enforced by not permitting checked
+ * exceptions such as {@code IOExceptions} to be thrown. However,
+ * computations may still encounter unchecked exceptions, that are
+ * rethrown to callers attempting to join them. These exceptions may
+ * additionally include {@link RejectedExecutionException} stemming
+ * from internal resource exhaustion, such as failure to allocate
+ * internal task queues. Rethrown exceptions behave in the same way as
+ * regular exceptions, but, when possible, contain stack traces (as
+ * displayed for example using {@code ex.printStackTrace()}) of both
+ * the thread that initiated the computation as well as the thread
+ * actually encountering the exception; minimally only the latter.
+ *
+ * <p>The primary method for awaiting completion and extracting
+ * results of a task is {@link #join}, but there are several variants:
+ * The {@link Future#get} methods support interruptible and/or timed
+ * waits for completion and report results using {@code Future}
+ * conventions. Method {@link #invoke} is semantically
+ * equivalent to {@code fork(); join()} but always attempts to begin
+ * execution in the current thread. The "<em>quiet</em>" forms of
+ * these methods do not extract results or report exceptions. These
+ * may be useful when a set of tasks are being executed, and you need
+ * to delay processing of results or exceptions until all complete.
+ * Method {@code invokeAll} (available in multiple versions)
+ * performs the most common form of parallel invocation: forking a set
+ * of tasks and joining them all.
+ *
+ * <p>The execution status of tasks may be queried at several levels
+ * of detail: {@link #isDone} is true if a task completed in any way
+ * (including the case where a task was cancelled without executing);
+ * {@link #isCompletedNormally} is true if a task completed without
+ * cancellation or encountering an exception; {@link #isCancelled} is
+ * true if the task was cancelled (in which case {@link #getException}
+ * returns a {@link java.util.concurrent.CancellationException}); and
+ * {@link #isCompletedAbnormally} is true if a task was either
+ * cancelled or encountered an exception, in which case {@link
+ * #getException} will return either the encountered exception or
+ * {@link java.util.concurrent.CancellationException}.
+ *
+ * <p>The ForkJoinTask class is not usually directly subclassed.
+ * Instead, you subclass one of the abstract classes that support a
+ * particular style of fork/join processing, typically {@link
+ * RecursiveAction} for computations that do not return results, or
+ * {@link RecursiveTask} for those that do.  Normally, a concrete
+ * ForkJoinTask subclass declares fields comprising its parameters,
+ * established in a constructor, and then defines a {@code compute}
+ * method that somehow uses the control methods supplied by this base
+ * class. While these methods have {@code public} access (to allow
+ * instances of different task subclasses to call each other's
+ * methods), some of them may only be called from within other
+ * ForkJoinTasks (as may be determined using method {@link
+ * #inForkJoinPool}).  Attempts to invoke them in other contexts
+ * result in exceptions or errors, possibly including
+ * {@code ClassCastException}.
+ *
+ * <p>Method {@link #join} and its variants are appropriate for use
+ * only when completion dependencies are acyclic; that is, the
+ * parallel computation can be described as a directed acyclic graph
+ * (DAG). Otherwise, executions may encounter a form of deadlock as
+ * tasks cyclically wait for each other.  However, this framework
+ * supports other methods and techniques (for example the use of
+ * {@link Phaser}, {@link #helpQuiesce}, and {@link #complete}) that
+ * may be of use in constructing custom subclasses for problems that
+ * are not statically structured as DAGs.
+ *
+ * <p>Most base support methods are {@code final}, to prevent
+ * overriding of implementations that are intrinsically tied to the
+ * underlying lightweight task scheduling framework.  Developers
+ * creating new basic styles of fork/join processing should minimally
+ * implement {@code protected} methods {@link #exec}, {@link
+ * #setRawResult}, and {@link #getRawResult}, while also introducing
+ * an abstract computational method that can be implemented in its
+ * subclasses, possibly relying on other {@code protected} methods
+ * provided by this class.
+ *
+ * <p>ForkJoinTasks should perform relatively small amounts of
+ * computation. Large tasks should be split into smaller subtasks,
+ * usually via recursive decomposition. As a very rough rule of thumb,
+ * a task should perform more than 100 and less than 10000 basic
+ * computational steps, and should avoid indefinite looping. If tasks
+ * are too big, then parallelism cannot improve throughput. If too
+ * small, then memory and internal task maintenance overhead may
+ * overwhelm processing.
+ *
+ * <p>This class provides {@code adapt} methods for {@link Runnable}
+ * and {@link Callable}, that may be of use when mixing execution of
+ * {@code ForkJoinTasks} with other kinds of tasks. When all tasks are
+ * of this form, consider using a pool constructed in <em>asyncMode</em>.
+ *
+ * <p>ForkJoinTasks are {@code Serializable}, which enables them to be
+ * used in extensions such as remote execution frameworks. It is
+ * sensible to serialize tasks only before or after, but not during,
+ * execution. Serialization is not relied on during execution itself.
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ */
+public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
+
+    /*
+     * See the internal documentation of class ForkJoinPool for a
+     * general implementation overview.  ForkJoinTasks are mainly
+     * responsible for maintaining their "status" field amidst relays
+     * to methods in ForkJoinWorkerThread and ForkJoinPool.
+     *
+     * The methods of this class are more-or-less layered into
+     * (1) basic status maintenance
+     * (2) execution and awaiting completion
+     * (3) user-level methods that additionally report results.
+     * This is sometimes hard to see because this file orders exported
+     * methods in a way that flows well in javadocs.
+     */
+
+    /*
+     * The status field holds run control status bits packed into a
+     * single int to minimize footprint and to ensure atomicity (via
+     * CAS).  Status is initially zero, and takes on nonnegative
+     * values until completed, upon which status holds value
+     * NORMAL, CANCELLED, or EXCEPTIONAL. Tasks undergoing blocking
+     * waits by other threads have the SIGNAL bit set.  Completion of
+     * a stolen task with SIGNAL set awakens any waiters via
+     * notifyAll. Even though suboptimal for some purposes, we use
+     * basic builtin wait/notify to take advantage of "monitor
+     * inflation" in JVMs that we would otherwise need to emulate to
+     * avoid adding further per-task bookkeeping overhead.  We want
+     * these monitors to be "fat", i.e., not use biasing or thin-lock
+     * techniques, so use some odd coding idioms that tend to avoid
+     * them.
+     */
+
+    /** The run status of this task */
+    volatile int status; // accessed directly by pool and workers
+    private static final int NORMAL      = -1;
+    private static final int CANCELLED   = -2;
+    private static final int EXCEPTIONAL = -3;
+    private static final int SIGNAL      =  1;
+
+    /**
+     * Marks completion and wakes up threads waiting to join this task,
+     * also clearing signal request bits.
+     *
+     * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
+     * @return completion status on exit
+     */
+    private int setCompletion(int completion) {
+        for (int s;;) {
+            if ((s = status) < 0)
+                return s;
+            if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) {
+                if (s != 0)
+                    synchronized (this) { notifyAll(); }
+                return completion;
+            }
+        }
+    }
+
+    /**
+     * Tries to block a worker thread until completed or timed out.
+     * Uses Object.wait time argument conventions.
+     * May fail on contention or interrupt.
+     *
+     * @param millis if > 0, wait time.
+     */
+    final void tryAwaitDone(long millis) {
+        int s;
+        try {
+            if (((s = status) > 0 ||
+                 (s == 0 &&
+                  UNSAFE.compareAndSwapInt(this, statusOffset, 0, SIGNAL))) &&
+                status > 0) {
+                synchronized (this) {
+                    if (status > 0)
+                        wait(millis);
+                }
+            }
+        } catch (InterruptedException ie) {
+            // caller must check termination
+        }
+    }
+
+    /**
+     * Blocks a non-worker-thread until completion.
+     * @return status upon completion
+     */
+    private int externalAwaitDone() {
+        int s;
+        if ((s = status) >= 0) {
+            boolean interrupted = false;
+            synchronized (this) {
+                while ((s = status) >= 0) {
+                    if (s == 0)
+                        UNSAFE.compareAndSwapInt(this, statusOffset,
+                                                 0, SIGNAL);
+                    else {
+                        try {
+                            wait();
+                        } catch (InterruptedException ie) {
+                            interrupted = true;
+                        }
+                    }
+                }
+            }
+            if (interrupted)
+                Thread.currentThread().interrupt();
+        }
+        return s;
+    }
+
+    /**
+     * Blocks a non-worker-thread until completion or interruption or timeout.
+     */
+    private int externalInterruptibleAwaitDone(long millis)
+        throws InterruptedException {
+        int s;
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if ((s = status) >= 0) {
+            synchronized (this) {
+                while ((s = status) >= 0) {
+                    if (s == 0)
+                        UNSAFE.compareAndSwapInt(this, statusOffset,
+                                                 0, SIGNAL);
+                    else {
+                        wait(millis);
+                        if (millis > 0L)
+                            break;
+                    }
+                }
+            }
+        }
+        return s;
+    }
+
+    /**
+     * Primary execution method for stolen tasks. Unless done, calls
+     * exec and records status if completed, but doesn't wait for
+     * completion otherwise.
+     */
+    final void doExec() {
+        if (status >= 0) {
+            boolean completed;
+            try {
+                completed = exec();
+            } catch (Throwable rex) {
+                setExceptionalCompletion(rex);
+                return;
+            }
+            if (completed)
+                setCompletion(NORMAL); // must be outside try block
+        }
+    }
+
+    /**
+     * Primary mechanics for join, get, quietlyJoin.
+     * @return status upon completion
+     */
+    private int doJoin() {
+        Thread t; ForkJoinWorkerThread w; int s; boolean completed;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+            if ((s = status) < 0)
+                return s;
+            if ((w = (ForkJoinWorkerThread)t).unpushTask(this)) {
+                try {
+                    completed = exec();
+                } catch (Throwable rex) {
+                    return setExceptionalCompletion(rex);
+                }
+                if (completed)
+                    return setCompletion(NORMAL);
+            }
+            return w.joinTask(this);
+        }
+        else
+            return externalAwaitDone();
+    }
+
+    /**
+     * Primary mechanics for invoke, quietlyInvoke.
+     * @return status upon completion
+     */
+    private int doInvoke() {
+        int s; boolean completed;
+        if ((s = status) < 0)
+            return s;
+        try {
+            completed = exec();
+        } catch (Throwable rex) {
+            return setExceptionalCompletion(rex);
+        }
+        if (completed)
+            return setCompletion(NORMAL);
+        else
+            return doJoin();
+    }
+
+    // Exception table support
+
+    /**
+     * Table of exceptions thrown by tasks, to enable reporting by
+     * callers. Because exceptions are rare, we don't directly keep
+     * them with task objects, but instead use a weak ref table.  Note
+     * that cancellation exceptions don't appear in the table, but are
+     * instead recorded as status values.
+     *
+     * Note: These statics are initialized below in static block.
+     */
+    private static final ExceptionNode[] exceptionTable;
+    private static final ReentrantLock exceptionTableLock;
+    private static final ReferenceQueue<Object> exceptionTableRefQueue;
+
+    /**
+     * Fixed capacity for exceptionTable.
+     */
+    private static final int EXCEPTION_MAP_CAPACITY = 32;
+
+    /**
+     * Key-value nodes for exception table.  The chained hash table
+     * uses identity comparisons, full locking, and weak references
+     * for keys. The table has a fixed capacity because it only
+     * maintains task exceptions long enough for joiners to access
+     * them, so should never become very large for sustained
+     * periods. However, since we do not know when the last joiner
+     * completes, we must use weak references and expunge them. We do
+     * so on each operation (hence full locking). Also, some thread in
+     * any ForkJoinPool will call helpExpungeStaleExceptions when its
+     * pool becomes isQuiescent.
+     */
+    static final class ExceptionNode extends WeakReference<ForkJoinTask<?>>{
+        final Throwable ex;
+        ExceptionNode next;
+        final long thrower;  // use id not ref to avoid weak cycles
+        ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next) {
+            super(task, exceptionTableRefQueue);
+            this.ex = ex;
+            this.next = next;
+            this.thrower = Thread.currentThread().getId();
+        }
+    }
+
+    /**
+     * Records exception and sets exceptional completion.
+     *
+     * @return status on exit
+     */
+    private int setExceptionalCompletion(Throwable ex) {
+        int h = System.identityHashCode(this);
+        final ReentrantLock lock = exceptionTableLock;
+        lock.lock();
+        try {
+            expungeStaleExceptions();
+            ExceptionNode[] t = exceptionTable;
+            int i = h & (t.length - 1);
+            for (ExceptionNode e = t[i]; ; e = e.next) {
+                if (e == null) {
+                    t[i] = new ExceptionNode(this, ex, t[i]);
+                    break;
+                }
+                if (e.get() == this) // already present
+                    break;
+            }
+        } finally {
+            lock.unlock();
+        }
+        return setCompletion(EXCEPTIONAL);
+    }
+
+    /**
+     * Removes exception node and clears status
+     */
+    private void clearExceptionalCompletion() {
+        int h = System.identityHashCode(this);
+        final ReentrantLock lock = exceptionTableLock;
+        lock.lock();
+        try {
+            ExceptionNode[] t = exceptionTable;
+            int i = h & (t.length - 1);
+            ExceptionNode e = t[i];
+            ExceptionNode pred = null;
+            while (e != null) {
+                ExceptionNode next = e.next;
+                if (e.get() == this) {
+                    if (pred == null)
+                        t[i] = next;
+                    else
+                        pred.next = next;
+                    break;
+                }
+                pred = e;
+                e = next;
+            }
+            expungeStaleExceptions();
+            status = 0;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns a rethrowable exception for the given task, if
+     * available. To provide accurate stack traces, if the exception
+     * was not thrown by the current thread, we try to create a new
+     * exception of the same type as the one thrown, but with the
+     * recorded exception as its cause. If there is no such
+     * constructor, we instead try to use a no-arg constructor,
+     * followed by initCause, to the same effect. If none of these
+     * apply, or any fail due to other exceptions, we return the
+     * recorded exception, which is still correct, although it may
+     * contain a misleading stack trace.
+     *
+     * @return the exception, or null if none
+     */
+    private Throwable getThrowableException() {
+        if (status != EXCEPTIONAL)
+            return null;
+        int h = System.identityHashCode(this);
+        ExceptionNode e;
+        final ReentrantLock lock = exceptionTableLock;
+        lock.lock();
+        try {
+            expungeStaleExceptions();
+            ExceptionNode[] t = exceptionTable;
+            e = t[h & (t.length - 1)];
+            while (e != null && e.get() != this)
+                e = e.next;
+        } finally {
+            lock.unlock();
+        }
+        Throwable ex;
+        if (e == null || (ex = e.ex) == null)
+            return null;
+        if (e.thrower != Thread.currentThread().getId()) {
+            Class<? extends Throwable> ec = ex.getClass();
+            try {
+                Constructor<?> noArgCtor = null;
+                Constructor<?>[] cs = ec.getConstructors();// public ctors only
+                for (int i = 0; i < cs.length; ++i) {
+                    Constructor<?> c = cs[i];
+                    Class<?>[] ps = c.getParameterTypes();
+                    if (ps.length == 0)
+                        noArgCtor = c;
+                    else if (ps.length == 1 && ps[0] == Throwable.class)
+                        return (Throwable)(c.newInstance(ex));
+                }
+                if (noArgCtor != null) {
+                    Throwable wx = (Throwable)(noArgCtor.newInstance());
+                    wx.initCause(ex);
+                    return wx;
+                }
+            } catch (Exception ignore) {
+            }
+        }
+        return ex;
+    }
+
+    /**
+     * Poll stale refs and remove them. Call only while holding lock.
+     */
+    private static void expungeStaleExceptions() {
+        for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
+            if (x instanceof ExceptionNode) {
+                ForkJoinTask<?> key = ((ExceptionNode)x).get();
+                ExceptionNode[] t = exceptionTable;
+                int i = System.identityHashCode(key) & (t.length - 1);
+                ExceptionNode e = t[i];
+                ExceptionNode pred = null;
+                while (e != null) {
+                    ExceptionNode next = e.next;
+                    if (e == x) {
+                        if (pred == null)
+                            t[i] = next;
+                        else
+                            pred.next = next;
+                        break;
+                    }
+                    pred = e;
+                    e = next;
+                }
+            }
+        }
+    }
+
+    /**
+     * If lock is available, poll stale refs and remove them.
+     * Called from ForkJoinPool when pools become quiescent.
+     */
+    static final void helpExpungeStaleExceptions() {
+        final ReentrantLock lock = exceptionTableLock;
+        if (lock.tryLock()) {
+            try {
+                expungeStaleExceptions();
+            } finally {
+                lock.unlock();
+            }
+        }
+    }
+
+    /**
+     * Report the result of invoke or join; called only upon
+     * non-normal return of internal versions.
+     */
+    private V reportResult() {
+        int s; Throwable ex;
+        if ((s = status) == CANCELLED)
+            throw new CancellationException();
+        if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
+            SneakyThrow.sneakyThrow(ex); // android-changed
+        return getRawResult();
+    }
+
+    // public methods
+
+    /**
+     * Arranges to asynchronously execute this task.  While it is not
+     * necessarily enforced, it is a usage error to fork a task more
+     * than once unless it has completed and been reinitialized.
+     * Subsequent modifications to the state of this task or any data
+     * it operates on are not necessarily consistently observable by
+     * any thread other than the one executing it unless preceded by a
+     * call to {@link #join} or related methods, or a call to {@link
+     * #isDone} returning {@code true}.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @return {@code this}, to simplify usage
+     */
+    public final ForkJoinTask<V> fork() {
+        ((ForkJoinWorkerThread) Thread.currentThread())
+            .pushTask(this);
+        return this;
+    }
+
+    /**
+     * Returns the result of the computation when it {@link #isDone is
+     * done}.  This method differs from {@link #get()} in that
+     * abnormal completion results in {@code RuntimeException} or
+     * {@code Error}, not {@code ExecutionException}, and that
+     * interrupts of the calling thread do <em>not</em> cause the
+     * method to abruptly return by throwing {@code
+     * InterruptedException}.
+     *
+     * @return the computed result
+     */
+    public final V join() {
+        if (doJoin() != NORMAL)
+            return reportResult();
+        else
+            return getRawResult();
+    }
+
+    /**
+     * Commences performing this task, awaits its completion if
+     * necessary, and returns its result, or throws an (unchecked)
+     * {@code RuntimeException} or {@code Error} if the underlying
+     * computation did so.
+     *
+     * @return the computed result
+     */
+    public final V invoke() {
+        if (doInvoke() != NORMAL)
+            return reportResult();
+        else
+            return getRawResult();
+    }
+
+    /**
+     * Forks the given tasks, returning when {@code isDone} holds for
+     * each task or an (unchecked) exception is encountered, in which
+     * case the exception is rethrown. If more than one task
+     * encounters an exception, then this method throws any one of
+     * these exceptions. If any task encounters an exception, the
+     * other may be cancelled. However, the execution status of
+     * individual tasks is not guaranteed upon exceptional return. The
+     * status of each task may be obtained using {@link
+     * #getException()} and related methods to check if they have been
+     * cancelled, completed normally or exceptionally, or left
+     * unprocessed.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @param t1 the first task
+     * @param t2 the second task
+     * @throws NullPointerException if any task is null
+     */
+    public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
+        t2.fork();
+        t1.invoke();
+        t2.join();
+    }
+
+    /**
+     * Forks the given tasks, returning when {@code isDone} holds for
+     * each task or an (unchecked) exception is encountered, in which
+     * case the exception is rethrown. If more than one task
+     * encounters an exception, then this method throws any one of
+     * these exceptions. If any task encounters an exception, others
+     * may be cancelled. However, the execution status of individual
+     * tasks is not guaranteed upon exceptional return. The status of
+     * each task may be obtained using {@link #getException()} and
+     * related methods to check if they have been cancelled, completed
+     * normally or exceptionally, or left unprocessed.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @param tasks the tasks
+     * @throws NullPointerException if any task is null
+     */
+    public static void invokeAll(ForkJoinTask<?>... tasks) {
+        Throwable ex = null;
+        int last = tasks.length - 1;
+        for (int i = last; i >= 0; --i) {
+            ForkJoinTask<?> t = tasks[i];
+            if (t == null) {
+                if (ex == null)
+                    ex = new NullPointerException();
+            }
+            else if (i != 0)
+                t.fork();
+            else if (t.doInvoke() < NORMAL && ex == null)
+                ex = t.getException();
+        }
+        for (int i = 1; i <= last; ++i) {
+            ForkJoinTask<?> t = tasks[i];
+            if (t != null) {
+                if (ex != null)
+                    t.cancel(false);
+                else if (t.doJoin() < NORMAL)
+                    ex = t.getException();
+            }
+        }
+        if (ex != null)
+            SneakyThrow.sneakyThrow(ex); // android-changed
+    }
+
+    /**
+     * Forks all tasks in the specified collection, returning when
+     * {@code isDone} holds for each task or an (unchecked) exception
+     * is encountered, in which case the exception is rethrown. If
+     * more than one task encounters an exception, then this method
+     * throws any one of these exceptions. If any task encounters an
+     * exception, others may be cancelled. However, the execution
+     * status of individual tasks is not guaranteed upon exceptional
+     * return. The status of each task may be obtained using {@link
+     * #getException()} and related methods to check if they have been
+     * cancelled, completed normally or exceptionally, or left
+     * unprocessed.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @param tasks the collection of tasks
+     * @return the tasks argument, to simplify usage
+     * @throws NullPointerException if tasks or any element are null
+     */
+    public static <T extends ForkJoinTask<?>> Collection<T> invokeAll(Collection<T> tasks) {
+        if (!(tasks instanceof RandomAccess) || !(tasks instanceof List<?>)) {
+            invokeAll(tasks.toArray(new ForkJoinTask<?>[tasks.size()]));
+            return tasks;
+        }
+        @SuppressWarnings("unchecked")
+        List<? extends ForkJoinTask<?>> ts =
+            (List<? extends ForkJoinTask<?>>) tasks;
+        Throwable ex = null;
+        int last = ts.size() - 1;
+        for (int i = last; i >= 0; --i) {
+            ForkJoinTask<?> t = ts.get(i);
+            if (t == null) {
+                if (ex == null)
+                    ex = new NullPointerException();
+            }
+            else if (i != 0)
+                t.fork();
+            else if (t.doInvoke() < NORMAL && ex == null)
+                ex = t.getException();
+        }
+        for (int i = 1; i <= last; ++i) {
+            ForkJoinTask<?> t = ts.get(i);
+            if (t != null) {
+                if (ex != null)
+                    t.cancel(false);
+                else if (t.doJoin() < NORMAL)
+                    ex = t.getException();
+            }
+        }
+        if (ex != null)
+            SneakyThrow.sneakyThrow(ex); // android-changed
+        return tasks;
+    }
+
+    /**
+     * Attempts to cancel execution of this task. This attempt will
+     * fail if the task has already completed or could not be
+     * cancelled for some other reason. If successful, and this task
+     * has not started when {@code cancel} is called, execution of
+     * this task is suppressed. After this method returns
+     * successfully, unless there is an intervening call to {@link
+     * #reinitialize}, subsequent calls to {@link #isCancelled},
+     * {@link #isDone}, and {@code cancel} will return {@code true}
+     * and calls to {@link #join} and related methods will result in
+     * {@code CancellationException}.
+     *
+     * <p>This method may be overridden in subclasses, but if so, must
+     * still ensure that these properties hold. In particular, the
+     * {@code cancel} method itself must not throw exceptions.
+     *
+     * <p>This method is designed to be invoked by <em>other</em>
+     * tasks. To terminate the current task, you can just return or
+     * throw an unchecked exception from its computation method, or
+     * invoke {@link #completeExceptionally}.
+     *
+     * @param mayInterruptIfRunning this value has no effect in the
+     * default implementation because interrupts are not used to
+     * control cancellation.
+     *
+     * @return {@code true} if this task is now cancelled
+     */
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        return setCompletion(CANCELLED) == CANCELLED;
+    }
+
+    /**
+     * Cancels, ignoring any exceptions thrown by cancel. Used during
+     * worker and pool shutdown. Cancel is spec'ed not to throw any
+     * exceptions, but if it does anyway, we have no recourse during
+     * shutdown, so guard against this case.
+     */
+    final void cancelIgnoringExceptions() {
+        try {
+            cancel(false);
+        } catch (Throwable ignore) {
+        }
+    }
+
+    public final boolean isDone() {
+        return status < 0;
+    }
+
+    public final boolean isCancelled() {
+        return status == CANCELLED;
+    }
+
+    /**
+     * Returns {@code true} if this task threw an exception or was cancelled.
+     *
+     * @return {@code true} if this task threw an exception or was cancelled
+     */
+    public final boolean isCompletedAbnormally() {
+        return status < NORMAL;
+    }
+
+    /**
+     * Returns {@code true} if this task completed without throwing an
+     * exception and was not cancelled.
+     *
+     * @return {@code true} if this task completed without throwing an
+     * exception and was not cancelled
+     */
+    public final boolean isCompletedNormally() {
+        return status == NORMAL;
+    }
+
+    /**
+     * Returns the exception thrown by the base computation, or a
+     * {@code CancellationException} if cancelled, or {@code null} if
+     * none or if the method has not yet completed.
+     *
+     * @return the exception, or {@code null} if none
+     */
+    public final Throwable getException() {
+        int s = status;
+        return ((s >= NORMAL)    ? null :
+                (s == CANCELLED) ? new CancellationException() :
+                getThrowableException());
+    }
+
+    /**
+     * Completes this task abnormally, and if not already aborted or
+     * cancelled, causes it to throw the given exception upon
+     * {@code join} and related operations. This method may be used
+     * to induce exceptions in asynchronous tasks, or to force
+     * completion of tasks that would not otherwise complete.  Its use
+     * in other situations is discouraged.  This method is
+     * overridable, but overridden versions must invoke {@code super}
+     * implementation to maintain guarantees.
+     *
+     * @param ex the exception to throw. If this exception is not a
+     * {@code RuntimeException} or {@code Error}, the actual exception
+     * thrown will be a {@code RuntimeException} with cause {@code ex}.
+     */
+    public void completeExceptionally(Throwable ex) {
+        setExceptionalCompletion((ex instanceof RuntimeException) ||
+                                 (ex instanceof Error) ? ex :
+                                 new RuntimeException(ex));
+    }
+
+    /**
+     * Completes this task, and if not already aborted or cancelled,
+     * returning the given value as the result of subsequent
+     * invocations of {@code join} and related operations. This method
+     * may be used to provide results for asynchronous tasks, or to
+     * provide alternative handling for tasks that would not otherwise
+     * complete normally. Its use in other situations is
+     * discouraged. This method is overridable, but overridden
+     * versions must invoke {@code super} implementation to maintain
+     * guarantees.
+     *
+     * @param value the result value for this task
+     */
+    public void complete(V value) {
+        try {
+            setRawResult(value);
+        } catch (Throwable rex) {
+            setExceptionalCompletion(rex);
+            return;
+        }
+        setCompletion(NORMAL);
+    }
+
+    /**
+     * Waits if necessary for the computation to complete, and then
+     * retrieves its result.
+     *
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread is not a
+     * member of a ForkJoinPool and was interrupted while waiting
+     */
+    public final V get() throws InterruptedException, ExecutionException {
+        int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
+            doJoin() : externalInterruptibleAwaitDone(0L);
+        Throwable ex;
+        if (s == CANCELLED)
+            throw new CancellationException();
+        if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
+            throw new ExecutionException(ex);
+        return getRawResult();
+    }
+
+    /**
+     * Waits if necessary for at most the given time for the computation
+     * to complete, and then retrieves its result, if available.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread is not a
+     * member of a ForkJoinPool and was interrupted while waiting
+     * @throws TimeoutException if the wait timed out
+     */
+    public final V get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        Thread t = Thread.currentThread();
+        if (t instanceof ForkJoinWorkerThread) {
+            ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
+            long nanos = unit.toNanos(timeout);
+            if (status >= 0) {
+                boolean completed = false;
+                if (w.unpushTask(this)) {
+                    try {
+                        completed = exec();
+                    } catch (Throwable rex) {
+                        setExceptionalCompletion(rex);
+                    }
+                }
+                if (completed)
+                    setCompletion(NORMAL);
+                else if (status >= 0 && nanos > 0)
+                    w.pool.timedAwaitJoin(this, nanos);
+            }
+        }
+        else {
+            long millis = unit.toMillis(timeout);
+            if (millis > 0)
+                externalInterruptibleAwaitDone(millis);
+        }
+        int s = status;
+        if (s != NORMAL) {
+            Throwable ex;
+            if (s == CANCELLED)
+                throw new CancellationException();
+            if (s != EXCEPTIONAL)
+                throw new TimeoutException();
+            if ((ex = getThrowableException()) != null)
+                throw new ExecutionException(ex);
+        }
+        return getRawResult();
+    }
+
+    /**
+     * Joins this task, without returning its result or throwing its
+     * exception. This method may be useful when processing
+     * collections of tasks when some have been cancelled or otherwise
+     * known to have aborted.
+     */
+    public final void quietlyJoin() {
+        doJoin();
+    }
+
+    /**
+     * Commences performing this task and awaits its completion if
+     * necessary, without returning its result or throwing its
+     * exception.
+     */
+    public final void quietlyInvoke() {
+        doInvoke();
+    }
+
+    /**
+     * Possibly executes tasks until the pool hosting the current task
+     * {@link ForkJoinPool#isQuiescent is quiescent}. This method may
+     * be of use in designs in which many tasks are forked, but none
+     * are explicitly joined, instead executing them until all are
+     * processed.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     */
+    public static void helpQuiesce() {
+        ((ForkJoinWorkerThread) Thread.currentThread())
+            .helpQuiescePool();
+    }
+
+    /**
+     * Resets the internal bookkeeping state of this task, allowing a
+     * subsequent {@code fork}. This method allows repeated reuse of
+     * this task, but only if reuse occurs when this task has either
+     * never been forked, or has been forked, then completed and all
+     * outstanding joins of this task have also completed. Effects
+     * under any other usage conditions are not guaranteed.
+     * This method may be useful when executing
+     * pre-constructed trees of subtasks in loops.
+     *
+     * <p>Upon completion of this method, {@code isDone()} reports
+     * {@code false}, and {@code getException()} reports {@code
+     * null}. However, the value returned by {@code getRawResult} is
+     * unaffected. To clear this value, you can invoke {@code
+     * setRawResult(null)}.
+     */
+    public void reinitialize() {
+        if (status == EXCEPTIONAL)
+            clearExceptionalCompletion();
+        else
+            status = 0;
+    }
+
+    /**
+     * Returns the pool hosting the current task execution, or null
+     * if this task is executing outside of any ForkJoinPool.
+     *
+     * @see #inForkJoinPool
+     * @return the pool, or {@code null} if none
+     */
+    public static ForkJoinPool getPool() {
+        Thread t = Thread.currentThread();
+        return (t instanceof ForkJoinWorkerThread) ?
+            ((ForkJoinWorkerThread) t).pool : null;
+    }
+
+    /**
+     * Returns {@code true} if the current thread is a {@link
+     * ForkJoinWorkerThread} executing as a ForkJoinPool computation.
+     *
+     * @return {@code true} if the current thread is a {@link
+     * ForkJoinWorkerThread} executing as a ForkJoinPool computation,
+     * or {@code false} otherwise
+     */
+    public static boolean inForkJoinPool() {
+        return Thread.currentThread() instanceof ForkJoinWorkerThread;
+    }
+
+    /**
+     * Tries to unschedule this task for execution. This method will
+     * typically succeed if this task is the most recently forked task
+     * by the current thread, and has not commenced executing in
+     * another thread.  This method may be useful when arranging
+     * alternative local processing of tasks that could have been, but
+     * were not, stolen.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @return {@code true} if unforked
+     */
+    public boolean tryUnfork() {
+        return ((ForkJoinWorkerThread) Thread.currentThread())
+            .unpushTask(this);
+    }
+
+    /**
+     * Returns an estimate of the number of tasks that have been
+     * forked by the current worker thread but not yet executed. This
+     * value may be useful for heuristic decisions about whether to
+     * fork other tasks.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @return the number of tasks
+     */
+    public static int getQueuedTaskCount() {
+        return ((ForkJoinWorkerThread) Thread.currentThread())
+            .getQueueSize();
+    }
+
+    /**
+     * Returns an estimate of how many more locally queued tasks are
+     * held by the current worker thread than there are other worker
+     * threads that might steal them.  This value may be useful for
+     * heuristic decisions about whether to fork other tasks. In many
+     * usages of ForkJoinTasks, at steady state, each worker should
+     * aim to maintain a small constant surplus (for example, 3) of
+     * tasks, and to process computations locally if this threshold is
+     * exceeded.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @return the surplus number of tasks, which may be negative
+     */
+    public static int getSurplusQueuedTaskCount() {
+        return ((ForkJoinWorkerThread) Thread.currentThread())
+            .getEstimatedSurplusTaskCount();
+    }
+
+    // Extension methods
+
+    /**
+     * Returns the result that would be returned by {@link #join}, even
+     * if this task completed abnormally, or {@code null} if this task
+     * is not known to have been completed.  This method is designed
+     * to aid debugging, as well as to support extensions. Its use in
+     * any other context is discouraged.
+     *
+     * @return the result, or {@code null} if not completed
+     */
+    public abstract V getRawResult();
+
+    /**
+     * Forces the given value to be returned as a result.  This method
+     * is designed to support extensions, and should not in general be
+     * called otherwise.
+     *
+     * @param value the value
+     */
+    protected abstract void setRawResult(V value);
+
+    /**
+     * Immediately performs the base action of this task.  This method
+     * is designed to support extensions, and should not in general be
+     * called otherwise. The return value controls whether this task
+     * is considered to be done normally. It may return false in
+     * asynchronous actions that require explicit invocations of
+     * {@link #complete} to become joinable. It may also throw an
+     * (unchecked) exception to indicate abnormal exit.
+     *
+     * @return {@code true} if completed normally
+     */
+    protected abstract boolean exec();
+
+    /**
+     * Returns, but does not unschedule or execute, a task queued by
+     * the current thread but not yet executed, if one is immediately
+     * available. There is no guarantee that this task will actually
+     * be polled or executed next. Conversely, this method may return
+     * null even if a task exists but cannot be accessed without
+     * contention with other threads.  This method is designed
+     * primarily to support extensions, and is unlikely to be useful
+     * otherwise.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @return the next task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> peekNextLocalTask() {
+        return ((ForkJoinWorkerThread) Thread.currentThread())
+            .peekTask();
+    }
+
+    /**
+     * Unschedules and returns, without executing, the next task
+     * queued by the current thread but not yet executed.  This method
+     * is designed primarily to support extensions, and is unlikely to
+     * be useful otherwise.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @return the next task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> pollNextLocalTask() {
+        return ((ForkJoinWorkerThread) Thread.currentThread())
+            .pollLocalTask();
+    }
+
+    /**
+     * Unschedules and returns, without executing, the next task
+     * queued by the current thread but not yet executed, if one is
+     * available, or if not available, a task that was forked by some
+     * other thread, if available. Availability may be transient, so a
+     * {@code null} result does not necessarily imply quiescence
+     * of the pool this task is operating in.  This method is designed
+     * primarily to support extensions, and is unlikely to be useful
+     * otherwise.
+     *
+     * <p>This method may be invoked only from within {@code
+     * ForkJoinPool} computations (as may be determined using method
+     * {@link #inForkJoinPool}).  Attempts to invoke in other contexts
+     * result in exceptions or errors, possibly including {@code
+     * ClassCastException}.
+     *
+     * @return a task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> pollTask() {
+        return ((ForkJoinWorkerThread) Thread.currentThread())
+            .pollTask();
+    }
+
+    /**
+     * Adaptor for Runnables. This implements RunnableFuture
+     * to be compliant with AbstractExecutorService constraints
+     * when used in ForkJoinPool.
+     */
+    static final class AdaptedRunnable<T> extends ForkJoinTask<T>
+        implements RunnableFuture<T> {
+        final Runnable runnable;
+        final T resultOnCompletion;
+        T result;
+        AdaptedRunnable(Runnable runnable, T result) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+            this.resultOnCompletion = result;
+        }
+        public T getRawResult() { return result; }
+        public void setRawResult(T v) { result = v; }
+        public boolean exec() {
+            runnable.run();
+            result = resultOnCompletion;
+            return true;
+        }
+        public void run() { invoke(); }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adaptor for Callables
+     */
+    static final class AdaptedCallable<T> extends ForkJoinTask<T>
+        implements RunnableFuture<T> {
+        final Callable<? extends T> callable;
+        T result;
+        AdaptedCallable(Callable<? extends T> callable) {
+            if (callable == null) throw new NullPointerException();
+            this.callable = callable;
+        }
+        public T getRawResult() { return result; }
+        public void setRawResult(T v) { result = v; }
+        public boolean exec() {
+            try {
+                result = callable.call();
+                return true;
+            } catch (Error err) {
+                throw err;
+            } catch (RuntimeException rex) {
+                throw rex;
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        public void run() { invoke(); }
+        private static final long serialVersionUID = 2838392045355241008L;
+    }
+
+    /**
+     * Returns a new {@code ForkJoinTask} that performs the {@code run}
+     * method of the given {@code Runnable} as its action, and returns
+     * a null result upon {@link #join}.
+     *
+     * @param runnable the runnable action
+     * @return the task
+     */
+    public static ForkJoinTask<?> adapt(Runnable runnable) {
+        return new AdaptedRunnable<Void>(runnable, null);
+    }
+
+    /**
+     * Returns a new {@code ForkJoinTask} that performs the {@code run}
+     * method of the given {@code Runnable} as its action, and returns
+     * the given result upon {@link #join}.
+     *
+     * @param runnable the runnable action
+     * @param result the result upon completion
+     * @return the task
+     */
+    public static <T> ForkJoinTask<T> adapt(Runnable runnable, T result) {
+        return new AdaptedRunnable<T>(runnable, result);
+    }
+
+    /**
+     * Returns a new {@code ForkJoinTask} that performs the {@code call}
+     * method of the given {@code Callable} as its action, and returns
+     * its result upon {@link #join}, translating any checked exceptions
+     * encountered into {@code RuntimeException}.
+     *
+     * @param callable the callable action
+     * @return the task
+     */
+    public static <T> ForkJoinTask<T> adapt(Callable<? extends T> callable) {
+        return new AdaptedCallable<T>(callable);
+    }
+
+    // Serialization support
+
+    private static final long serialVersionUID = -7721805057305804111L;
+
+    /**
+     * Saves the state to a stream (that is, serializes it).
+     *
+     * @serialData the current run status and the exception thrown
+     * during execution, or {@code null} if none
+     * @param s the stream
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        s.defaultWriteObject();
+        s.writeObject(getException());
+    }
+
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     *
+     * @param s the stream
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        Object ex = s.readObject();
+        if (ex != null)
+            setExceptionalCompletion((Throwable)ex);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long statusOffset;
+    static {
+        exceptionTableLock = new ReentrantLock();
+        exceptionTableRefQueue = new ReferenceQueue<Object>();
+        exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
+        try {
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            statusOffset = UNSAFE.objectFieldOffset
+                (ForkJoinTask.class.getDeclaredField("status"));
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
new file mode 100644
index 0000000..d99ffe9
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
@@ -0,0 +1,970 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.concurrent.RejectedExecutionException;
+import libcore.util.SneakyThrow;
+
+/**
+ * A thread managed by a {@link ForkJoinPool}, which executes
+ * {@link ForkJoinTask}s.
+ * This class is subclassable solely for the sake of adding
+ * functionality -- there are no overridable methods dealing with
+ * scheduling or execution.  However, you can override initialization
+ * and termination methods surrounding the main task processing loop.
+ * If you do create such a subclass, you will also need to supply a
+ * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to use it
+ * in a {@code ForkJoinPool}.
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ */
+public class ForkJoinWorkerThread extends Thread {
+    /*
+     * Overview:
+     *
+     * ForkJoinWorkerThreads are managed by ForkJoinPools and perform
+     * ForkJoinTasks. This class includes bookkeeping in support of
+     * worker activation, suspension, and lifecycle control described
+     * in more detail in the internal documentation of class
+     * ForkJoinPool. And as described further below, this class also
+     * includes special-cased support for some ForkJoinTask
+     * methods. But the main mechanics involve work-stealing:
+     *
+     * Work-stealing queues are special forms of Deques that support
+     * only three of the four possible end-operations -- push, pop,
+     * and deq (aka steal), under the further constraints that push
+     * and pop are called only from the owning thread, while deq may
+     * be called from other threads.  (If you are unfamiliar with
+     * them, you probably want to read Herlihy and Shavit's book "The
+     * Art of Multiprocessor programming", chapter 16 describing these
+     * in more detail before proceeding.)  The main work-stealing
+     * queue design is roughly similar to those in the papers "Dynamic
+     * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005
+     * (http://research.sun.com/scalable/pubs/index.html) and
+     * "Idempotent work stealing" by Michael, Saraswat, and Vechev,
+     * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186).
+     * The main differences ultimately stem from gc requirements that
+     * we null out taken slots as soon as we can, to maintain as small
+     * a footprint as possible even in programs generating huge
+     * numbers of tasks. To accomplish this, we shift the CAS
+     * arbitrating pop vs deq (steal) from being on the indices
+     * ("queueBase" and "queueTop") to the slots themselves (mainly
+     * via method "casSlotNull()"). So, both a successful pop and deq
+     * mainly entail a CAS of a slot from non-null to null.  Because
+     * we rely on CASes of references, we do not need tag bits on
+     * queueBase or queueTop.  They are simple ints as used in any
+     * circular array-based queue (see for example ArrayDeque).
+     * Updates to the indices must still be ordered in a way that
+     * guarantees that queueTop == queueBase means the queue is empty,
+     * but otherwise may err on the side of possibly making the queue
+     * appear nonempty when a push, pop, or deq have not fully
+     * committed. Note that this means that the deq operation,
+     * considered individually, is not wait-free. One thief cannot
+     * successfully continue until another in-progress one (or, if
+     * previously empty, a push) completes.  However, in the
+     * aggregate, we ensure at least probabilistic non-blockingness.
+     * If an attempted steal fails, a thief always chooses a different
+     * random victim target to try next. So, in order for one thief to
+     * progress, it suffices for any in-progress deq or new push on
+     * any empty queue to complete.
+     *
+     * This approach also enables support for "async mode" where local
+     * task processing is in FIFO, not LIFO order; simply by using a
+     * version of deq rather than pop when locallyFifo is true (as set
+     * by the ForkJoinPool).  This allows use in message-passing
+     * frameworks in which tasks are never joined.  However neither
+     * mode considers affinities, loads, cache localities, etc, so
+     * rarely provide the best possible performance on a given
+     * machine, but portably provide good throughput by averaging over
+     * these factors.  (Further, even if we did try to use such
+     * information, we do not usually have a basis for exploiting
+     * it. For example, some sets of tasks profit from cache
+     * affinities, but others are harmed by cache pollution effects.)
+     *
+     * When a worker would otherwise be blocked waiting to join a
+     * task, it first tries a form of linear helping: Each worker
+     * records (in field currentSteal) the most recent task it stole
+     * from some other worker. Plus, it records (in field currentJoin)
+     * the task it is currently actively joining. Method joinTask uses
+     * these markers to try to find a worker to help (i.e., steal back
+     * a task from and execute it) that could hasten completion of the
+     * actively joined task. In essence, the joiner executes a task
+     * that would be on its own local deque had the to-be-joined task
+     * not been stolen. This may be seen as a conservative variant of
+     * the approach in Wagner & Calder "Leapfrogging: a portable
+     * technique for implementing efficient futures" SIGPLAN Notices,
+     * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs
+     * in that: (1) We only maintain dependency links across workers
+     * upon steals, rather than use per-task bookkeeping.  This may
+     * require a linear scan of workers array to locate stealers, but
+     * usually doesn't because stealers leave hints (that may become
+     * stale/wrong) of where to locate them. This isolates cost to
+     * when it is needed, rather than adding to per-task overhead.
+     * (2) It is "shallow", ignoring nesting and potentially cyclic
+     * mutual steals.  (3) It is intentionally racy: field currentJoin
+     * is updated only while actively joining, which means that we
+     * miss links in the chain during long-lived tasks, GC stalls etc
+     * (which is OK since blocking in such cases is usually a good
+     * idea).  (4) We bound the number of attempts to find work (see
+     * MAX_HELP) and fall back to suspending the worker and if
+     * necessary replacing it with another.
+     *
+     * Efficient implementation of these algorithms currently relies
+     * on an uncomfortable amount of "Unsafe" mechanics. To maintain
+     * correct orderings, reads and writes of variable queueBase
+     * require volatile ordering.  Variable queueTop need not be
+     * volatile because non-local reads always follow those of
+     * queueBase.  Similarly, because they are protected by volatile
+     * queueBase reads, reads of the queue array and its slots by
+     * other threads do not need volatile load semantics, but writes
+     * (in push) require store order and CASes (in pop and deq)
+     * require (volatile) CAS semantics.  (Michael, Saraswat, and
+     * Vechev's algorithm has similar properties, but without support
+     * for nulling slots.)  Since these combinations aren't supported
+     * using ordinary volatiles, the only way to accomplish these
+     * efficiently is to use direct Unsafe calls. (Using external
+     * AtomicIntegers and AtomicReferenceArrays for the indices and
+     * array is significantly slower because of memory locality and
+     * indirection effects.)
+     *
+     * Further, performance on most platforms is very sensitive to
+     * placement and sizing of the (resizable) queue array.  Even
+     * though these queues don't usually become all that big, the
+     * initial size must be large enough to counteract cache
+     * contention effects across multiple queues (especially in the
+     * presence of GC cardmarking). Also, to improve thread-locality,
+     * queues are initialized after starting.
+     */
+
+    /**
+     * Mask for pool indices encoded as shorts
+     */
+    private static final int  SMASK  = 0xffff;
+
+    /**
+     * Capacity of work-stealing queue array upon initialization.
+     * Must be a power of two. Initial size must be at least 4, but is
+     * padded to minimize cache effects.
+     */
+    private static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
+
+    /**
+     * Maximum size for queue array. Must be a power of two
+     * less than or equal to 1 << (31 - width of array entry) to
+     * ensure lack of index wraparound, but is capped at a lower
+     * value to help users trap runaway computations.
+     */
+    private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 24; // 16M
+
+    /**
+     * The work-stealing queue array. Size must be a power of two.
+     * Initialized when started (as opposed to when constructed), to
+     * improve memory locality.
+     */
+    ForkJoinTask<?>[] queue;
+
+    /**
+     * The pool this thread works in. Accessed directly by ForkJoinTask.
+     */
+    final ForkJoinPool pool;
+
+    /**
+     * Index (mod queue.length) of next queue slot to push to or pop
+     * from. It is written only by owner thread, and accessed by other
+     * threads only after reading (volatile) queueBase.  Both queueTop
+     * and queueBase are allowed to wrap around on overflow, but
+     * (queueTop - queueBase) still estimates size.
+     */
+    int queueTop;
+
+    /**
+     * Index (mod queue.length) of least valid queue slot, which is
+     * always the next position to steal from if nonempty.
+     */
+    volatile int queueBase;
+
+    /**
+     * The index of most recent stealer, used as a hint to avoid
+     * traversal in method helpJoinTask. This is only a hint because a
+     * worker might have had multiple steals and this only holds one
+     * of them (usually the most current). Declared non-volatile,
+     * relying on other prevailing sync to keep reasonably current.
+     */
+    int stealHint;
+
+    /**
+     * Index of this worker in pool array. Set once by pool before
+     * running, and accessed directly by pool to locate this worker in
+     * its workers array.
+     */
+    final int poolIndex;
+
+    /**
+     * Encoded record for pool task waits. Usages are always
+     * surrounded by volatile reads/writes
+     */
+    int nextWait;
+
+    /**
+     * Complement of poolIndex, offset by count of entries of task
+     * waits. Accessed by ForkJoinPool to manage event waiters.
+     */
+    volatile int eventCount;
+
+    /**
+     * Seed for random number generator for choosing steal victims.
+     * Uses Marsaglia xorshift. Must be initialized as nonzero.
+     */
+    int seed;
+
+    /**
+     * Number of steals. Directly accessed (and reset) by pool when
+     * idle.
+     */
+    int stealCount;
+
+    /**
+     * True if this worker should or did terminate
+     */
+    volatile boolean terminate;
+
+    /**
+     * Set to true before LockSupport.park; false on return
+     */
+    volatile boolean parked;
+
+    /**
+     * True if use local fifo, not default lifo, for local polling.
+     * Shadows value from ForkJoinPool.
+     */
+    final boolean locallyFifo;
+
+    /**
+     * The task most recently stolen from another worker (or
+     * submission queue).  All uses are surrounded by enough volatile
+     * reads/writes to maintain as non-volatile.
+     */
+    ForkJoinTask<?> currentSteal;
+
+    /**
+     * The task currently being joined, set only when actively trying
+     * to help other stealers in helpJoinTask. All uses are surrounded
+     * by enough volatile reads/writes to maintain as non-volatile.
+     */
+    ForkJoinTask<?> currentJoin;
+
+    /**
+     * Creates a ForkJoinWorkerThread operating in the given pool.
+     *
+     * @param pool the pool this thread works in
+     * @throws NullPointerException if pool is null
+     */
+    protected ForkJoinWorkerThread(ForkJoinPool pool) {
+        super(pool.nextWorkerName());
+        this.pool = pool;
+        int k = pool.registerWorker(this);
+        poolIndex = k;
+        eventCount = ~k & SMASK; // clear wait count
+        locallyFifo = pool.locallyFifo;
+        Thread.UncaughtExceptionHandler ueh = pool.ueh;
+        if (ueh != null)
+            setUncaughtExceptionHandler(ueh);
+        setDaemon(true);
+    }
+
+    // Public methods
+
+    /**
+     * Returns the pool hosting this thread.
+     *
+     * @return the pool
+     */
+    public ForkJoinPool getPool() {
+        return pool;
+    }
+
+    /**
+     * Returns the index number of this thread in its pool.  The
+     * returned value ranges from zero to the maximum number of
+     * threads (minus one) that have ever been created in the pool.
+     * This method may be useful for applications that track status or
+     * collect results per-worker rather than per-task.
+     *
+     * @return the index number
+     */
+    public int getPoolIndex() {
+        return poolIndex;
+    }
+
+    // Randomization
+
+    /**
+     * Computes next value for random victim probes and backoffs.
+     * Scans don't require a very high quality generator, but also not
+     * a crummy one.  Marsaglia xor-shift is cheap and works well
+     * enough.  Note: This is manually inlined in FJP.scan() to avoid
+     * writes inside busy loops.
+     */
+    private int nextSeed() {
+        int r = seed;
+        r ^= r << 13;
+        r ^= r >>> 17;
+        r ^= r << 5;
+        return seed = r;
+    }
+
+    // Run State management
+
+    /**
+     * Initializes internal state after construction but before
+     * processing any tasks. If you override this method, you must
+     * invoke {@code super.onStart()} at the beginning of the method.
+     * Initialization requires care: Most fields must have legal
+     * default values, to ensure that attempted accesses from other
+     * threads work correctly even before this thread starts
+     * processing tasks.
+     */
+    protected void onStart() {
+        queue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
+        int r = ForkJoinPool.workerSeedGenerator.nextInt();
+        seed = (r == 0) ? 1 : r; //  must be nonzero
+    }
+
+    /**
+     * Performs cleanup associated with termination of this worker
+     * thread.  If you override this method, you must invoke
+     * {@code super.onTermination} at the end of the overridden method.
+     *
+     * @param exception the exception causing this thread to abort due
+     * to an unrecoverable error, or {@code null} if completed normally
+     */
+    protected void onTermination(Throwable exception) {
+        try {
+            terminate = true;
+            cancelTasks();
+            pool.deregisterWorker(this, exception);
+        } catch (Throwable ex) {        // Shouldn't ever happen
+            if (exception == null)      // but if so, at least rethrown
+                exception = ex;
+        } finally {
+            if (exception != null)
+                SneakyThrow.sneakyThrow(exception); // android-changed
+        }
+    }
+
+    /**
+     * This method is required to be public, but should never be
+     * called explicitly. It performs the main run loop to execute
+     * {@link ForkJoinTask}s.
+     */
+    public void run() {
+        Throwable exception = null;
+        try {
+            onStart();
+            pool.work(this);
+        } catch (Throwable ex) {
+            exception = ex;
+        } finally {
+            onTermination(exception);
+        }
+    }
+
+    /*
+     * Intrinsics-based atomic writes for queue slots. These are
+     * basically the same as methods in AtomicReferenceArray, but
+     * specialized for (1) ForkJoinTask elements (2) requirement that
+     * nullness and bounds checks have already been performed by
+     * callers and (3) effective offsets are known not to overflow
+     * from int to long (because of MAXIMUM_QUEUE_CAPACITY). We don't
+     * need corresponding version for reads: plain array reads are OK
+     * because they are protected by other volatile reads and are
+     * confirmed by CASes.
+     *
+     * Most uses don't actually call these methods, but instead
+     * contain inlined forms that enable more predictable
+     * optimization.  We don't define the version of write used in
+     * pushTask at all, but instead inline there a store-fenced array
+     * slot write.
+     *
+     * Also in most methods, as a performance (not correctness) issue,
+     * we'd like to encourage compilers not to arbitrarily postpone
+     * setting queueTop after writing slot.  Currently there is no
+     * intrinsic for arranging this, but using Unsafe putOrderedInt
+     * may be a preferable strategy on some compilers even though its
+     * main effect is a pre-, not post- fence. To simplify possible
+     * changes, the option is left in comments next to the associated
+     * assignments.
+     */
+
+    /**
+     * CASes slot i of array q from t to null. Caller must ensure q is
+     * non-null and index is in range.
+     */
+    private static final boolean casSlotNull(ForkJoinTask<?>[] q, int i,
+                                             ForkJoinTask<?> t) {
+        return UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, t, null);
+    }
+
+    /**
+     * Performs a volatile write of the given task at given slot of
+     * array q.  Caller must ensure q is non-null and index is in
+     * range. This method is used only during resets and backouts.
+     */
+    private static final void writeSlot(ForkJoinTask<?>[] q, int i,
+                                        ForkJoinTask<?> t) {
+        UNSAFE.putObjectVolatile(q, (i << ASHIFT) + ABASE, t);
+    }
+
+    // queue methods
+
+    /**
+     * Pushes a task. Call only from this thread.
+     *
+     * @param t the task. Caller must ensure non-null.
+     */
+    final void pushTask(ForkJoinTask<?> t) {
+        ForkJoinTask<?>[] q; int s, m;
+        if ((q = queue) != null) {    // ignore if queue removed
+            long u = (((s = queueTop) & (m = q.length - 1)) << ASHIFT) + ABASE;
+            UNSAFE.putOrderedObject(q, u, t);
+            queueTop = s + 1;         // or use putOrderedInt
+            if ((s -= queueBase) <= 2)
+                pool.signalWork();
+            else if (s == m)
+                growQueue();
+        }
+    }
+
+    /**
+     * Creates or doubles queue array.  Transfers elements by
+     * emulating steals (deqs) from old array and placing, oldest
+     * first, into new array.
+     */
+    private void growQueue() {
+        ForkJoinTask<?>[] oldQ = queue;
+        int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY;
+        if (size > MAXIMUM_QUEUE_CAPACITY)
+            throw new RejectedExecutionException("Queue capacity exceeded");
+        if (size < INITIAL_QUEUE_CAPACITY)
+            size = INITIAL_QUEUE_CAPACITY;
+        ForkJoinTask<?>[] q = queue = new ForkJoinTask<?>[size];
+        int mask = size - 1;
+        int top = queueTop;
+        int oldMask;
+        if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) {
+            for (int b = queueBase; b != top; ++b) {
+                long u = ((b & oldMask) << ASHIFT) + ABASE;
+                Object x = UNSAFE.getObjectVolatile(oldQ, u);
+                if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null))
+                    UNSAFE.putObjectVolatile
+                        (q, ((b & mask) << ASHIFT) + ABASE, x);
+            }
+        }
+    }
+
+    /**
+     * Tries to take a task from the base of the queue, failing if
+     * empty or contended. Note: Specializations of this code appear
+     * in locallyDeqTask and elsewhere.
+     *
+     * @return a task, or null if none or contended
+     */
+    final ForkJoinTask<?> deqTask() {
+        ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
+        if (queueTop != (b = queueBase) &&
+            (q = queue) != null && // must read q after b
+            (i = (q.length - 1) & b) >= 0 &&
+            (t = q[i]) != null && queueBase == b &&
+            UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, t, null)) {
+            queueBase = b + 1;
+            return t;
+        }
+        return null;
+    }
+
+    /**
+     * Tries to take a task from the base of own queue.  Called only
+     * by this thread.
+     *
+     * @return a task, or null if none
+     */
+    final ForkJoinTask<?> locallyDeqTask() {
+        ForkJoinTask<?> t; int m, b, i;
+        ForkJoinTask<?>[] q = queue;
+        if (q != null && (m = q.length - 1) >= 0) {
+            while (queueTop != (b = queueBase)) {
+                if ((t = q[i = m & b]) != null &&
+                    queueBase == b &&
+                    UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE,
+                                                t, null)) {
+                    queueBase = b + 1;
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a popped task, or null if empty.
+     * Called only by this thread.
+     */
+    private ForkJoinTask<?> popTask() {
+        int m;
+        ForkJoinTask<?>[] q = queue;
+        if (q != null && (m = q.length - 1) >= 0) {
+            for (int s; (s = queueTop) != queueBase;) {
+                int i = m & --s;
+                long u = (i << ASHIFT) + ABASE; // raw offset
+                ForkJoinTask<?> t = q[i];
+                if (t == null)   // lost to stealer
+                    break;
+                if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
+                    queueTop = s; // or putOrderedInt
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Specialized version of popTask to pop only if topmost element
+     * is the given task. Called only by this thread.
+     *
+     * @param t the task. Caller must ensure non-null.
+     */
+    final boolean unpushTask(ForkJoinTask<?> t) {
+        ForkJoinTask<?>[] q;
+        int s;
+        if ((q = queue) != null && (s = queueTop) != queueBase &&
+            UNSAFE.compareAndSwapObject
+            (q, (((q.length - 1) & --s) << ASHIFT) + ABASE, t, null)) {
+            queueTop = s; // or putOrderedInt
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns next task, or null if empty or contended.
+     */
+    final ForkJoinTask<?> peekTask() {
+        int m;
+        ForkJoinTask<?>[] q = queue;
+        if (q == null || (m = q.length - 1) < 0)
+            return null;
+        int i = locallyFifo ? queueBase : (queueTop - 1);
+        return q[i & m];
+    }
+
+    // Support methods for ForkJoinPool
+
+    /**
+     * Runs the given task, plus any local tasks until queue is empty
+     */
+    final void execTask(ForkJoinTask<?> t) {
+        currentSteal = t;
+        for (;;) {
+            if (t != null)
+                t.doExec();
+            if (queueTop == queueBase)
+                break;
+            t = locallyFifo ? locallyDeqTask() : popTask();
+        }
+        ++stealCount;
+        currentSteal = null;
+    }
+
+    /**
+     * Removes and cancels all tasks in queue.  Can be called from any
+     * thread.
+     */
+    final void cancelTasks() {
+        ForkJoinTask<?> cj = currentJoin; // try to cancel ongoing tasks
+        if (cj != null && cj.status >= 0)
+            cj.cancelIgnoringExceptions();
+        ForkJoinTask<?> cs = currentSteal;
+        if (cs != null && cs.status >= 0)
+            cs.cancelIgnoringExceptions();
+        while (queueBase != queueTop) {
+            ForkJoinTask<?> t = deqTask();
+            if (t != null)
+                t.cancelIgnoringExceptions();
+        }
+    }
+
+    /**
+     * Drains tasks to given collection c.
+     *
+     * @return the number of tasks drained
+     */
+    final int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
+        int n = 0;
+        while (queueBase != queueTop) {
+            ForkJoinTask<?> t = deqTask();
+            if (t != null) {
+                c.add(t);
+                ++n;
+            }
+        }
+        return n;
+    }
+
+    // Support methods for ForkJoinTask
+
+    /**
+     * Returns an estimate of the number of tasks in the queue.
+     */
+    final int getQueueSize() {
+        return queueTop - queueBase;
+    }
+
+    /**
+     * Gets and removes a local task.
+     *
+     * @return a task, if available
+     */
+    final ForkJoinTask<?> pollLocalTask() {
+        return locallyFifo ? locallyDeqTask() : popTask();
+    }
+
+    /**
+     * Gets and removes a local or stolen task.
+     *
+     * @return a task, if available
+     */
+    final ForkJoinTask<?> pollTask() {
+        ForkJoinWorkerThread[] ws;
+        ForkJoinTask<?> t = pollLocalTask();
+        if (t != null || (ws = pool.workers) == null)
+            return t;
+        int n = ws.length; // cheap version of FJP.scan
+        int steps = n << 1;
+        int r = nextSeed();
+        int i = 0;
+        while (i < steps) {
+            ForkJoinWorkerThread w = ws[(i++ + r) & (n - 1)];
+            if (w != null && w.queueBase != w.queueTop && w.queue != null) {
+                if ((t = w.deqTask()) != null)
+                    return t;
+                i = 0;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * The maximum stolen->joining link depth allowed in helpJoinTask,
+     * as well as the maximum number of retries (allowing on average
+     * one staleness retry per level) per attempt to instead try
+     * compensation.  Depths for legitimate chains are unbounded, but
+     * we use a fixed constant to avoid (otherwise unchecked) cycles
+     * and bound staleness of traversal parameters at the expense of
+     * sometimes blocking when we could be helping.
+     */
+    private static final int MAX_HELP = 16;
+
+    /**
+     * Possibly runs some tasks and/or blocks, until joinMe is done.
+     *
+     * @param joinMe the task to join
+     * @return completion status on exit
+     */
+    final int joinTask(ForkJoinTask<?> joinMe) {
+        ForkJoinTask<?> prevJoin = currentJoin;
+        currentJoin = joinMe;
+        for (int s, retries = MAX_HELP;;) {
+            if ((s = joinMe.status) < 0) {
+                currentJoin = prevJoin;
+                return s;
+            }
+            if (retries > 0) {
+                if (queueTop != queueBase) {
+                    if (!localHelpJoinTask(joinMe))
+                        retries = 0;           // cannot help
+                }
+                else if (retries == MAX_HELP >>> 1) {
+                    --retries;                 // check uncommon case
+                    if (tryDeqAndExec(joinMe) >= 0)
+                        Thread.yield();        // for politeness
+                }
+                else
+                    retries = helpJoinTask(joinMe) ? MAX_HELP : retries - 1;
+            }
+            else {
+                retries = MAX_HELP;           // restart if not done
+                pool.tryAwaitJoin(joinMe);
+            }
+        }
+    }
+
+    /**
+     * If present, pops and executes the given task, or any other
+     * cancelled task
+     *
+     * @return false if any other non-cancelled task exists in local queue
+     */
+    private boolean localHelpJoinTask(ForkJoinTask<?> joinMe) {
+        int s, i; ForkJoinTask<?>[] q; ForkJoinTask<?> t;
+        if ((s = queueTop) != queueBase && (q = queue) != null &&
+            (i = (q.length - 1) & --s) >= 0 &&
+            (t = q[i]) != null) {
+            if (t != joinMe && t.status >= 0)
+                return false;
+            if (UNSAFE.compareAndSwapObject
+                (q, (i << ASHIFT) + ABASE, t, null)) {
+                queueTop = s;           // or putOrderedInt
+                t.doExec();
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Tries to locate and execute tasks for a stealer of the given
+     * task, or in turn one of its stealers, Traces
+     * currentSteal->currentJoin links looking for a thread working on
+     * a descendant of the given task and with a non-empty queue to
+     * steal back and execute tasks from.  The implementation is very
+     * branchy to cope with potential inconsistencies or loops
+     * encountering chains that are stale, unknown, or of length
+     * greater than MAX_HELP links.  All of these cases are dealt with
+     * by just retrying by caller.
+     *
+     * @param joinMe the task to join
+     * @return true if ran a task
+     */
+    private boolean helpJoinTask(ForkJoinTask<?> joinMe) {
+        boolean helped = false;
+        int m = pool.scanGuard & SMASK;
+        ForkJoinWorkerThread[] ws = pool.workers;
+        if (ws != null && ws.length > m && joinMe.status >= 0) {
+            int levels = MAX_HELP;              // remaining chain length
+            ForkJoinTask<?> task = joinMe;      // base of chain
+            outer:for (ForkJoinWorkerThread thread = this;;) {
+                // Try to find v, the stealer of task, by first using hint
+                ForkJoinWorkerThread v = ws[thread.stealHint & m];
+                if (v == null || v.currentSteal != task) {
+                    for (int j = 0; ;) {        // search array
+                        if ((v = ws[j]) != null && v.currentSteal == task) {
+                            thread.stealHint = j;
+                            break;              // save hint for next time
+                        }
+                        if (++j > m)
+                            break outer;        // can't find stealer
+                    }
+                }
+                // Try to help v, using specialized form of deqTask
+                for (;;) {
+                    ForkJoinTask<?>[] q; int b, i;
+                    if (joinMe.status < 0)
+                        break outer;
+                    if ((b = v.queueBase) == v.queueTop ||
+                        (q = v.queue) == null ||
+                        (i = (q.length-1) & b) < 0)
+                        break;                  // empty
+                    long u = (i << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = q[i];
+                    if (task.status < 0)
+                        break outer;            // stale
+                    if (t != null && v.queueBase == b &&
+                        UNSAFE.compareAndSwapObject(q, u, t, null)) {
+                        v.queueBase = b + 1;
+                        v.stealHint = poolIndex;
+                        ForkJoinTask<?> ps = currentSteal;
+                        currentSteal = t;
+                        t.doExec();
+                        currentSteal = ps;
+                        helped = true;
+                    }
+                }
+                // Try to descend to find v's stealer
+                ForkJoinTask<?> next = v.currentJoin;
+                if (--levels > 0 && task.status >= 0 &&
+                    next != null && next != task) {
+                    task = next;
+                    thread = v;
+                }
+                else
+                    break;  // max levels, stale, dead-end, or cyclic
+            }
+        }
+        return helped;
+    }
+
+    /**
+     * Performs an uncommon case for joinTask: If task t is at base of
+     * some workers queue, steals and executes it.
+     *
+     * @param t the task
+     * @return t's status
+     */
+    private int tryDeqAndExec(ForkJoinTask<?> t) {
+        int m = pool.scanGuard & SMASK;
+        ForkJoinWorkerThread[] ws = pool.workers;
+        if (ws != null && ws.length > m && t.status >= 0) {
+            for (int j = 0; j <= m; ++j) {
+                ForkJoinTask<?>[] q; int b, i;
+                ForkJoinWorkerThread v = ws[j];
+                if (v != null &&
+                    (b = v.queueBase) != v.queueTop &&
+                    (q = v.queue) != null &&
+                    (i = (q.length - 1) & b) >= 0 &&
+                    q[i] ==  t) {
+                    long u = (i << ASHIFT) + ABASE;
+                    if (v.queueBase == b &&
+                        UNSAFE.compareAndSwapObject(q, u, t, null)) {
+                        v.queueBase = b + 1;
+                        v.stealHint = poolIndex;
+                        ForkJoinTask<?> ps = currentSteal;
+                        currentSteal = t;
+                        t.doExec();
+                        currentSteal = ps;
+                    }
+                    break;
+                }
+            }
+        }
+        return t.status;
+    }
+
+    /**
+     * Implements ForkJoinTask.getSurplusQueuedTaskCount().  Returns
+     * an estimate of the number of tasks, offset by a function of
+     * number of idle workers.
+     *
+     * This method provides a cheap heuristic guide for task
+     * partitioning when programmers, frameworks, tools, or languages
+     * have little or no idea about task granularity.  In essence by
+     * offering this method, we ask users only about tradeoffs in
+     * overhead vs expected throughput and its variance, rather than
+     * how finely to partition tasks.
+     *
+     * In a steady state strict (tree-structured) computation, each
+     * thread makes available for stealing enough tasks for other
+     * threads to remain active. Inductively, if all threads play by
+     * the same rules, each thread should make available only a
+     * constant number of tasks.
+     *
+     * The minimum useful constant is just 1. But using a value of 1
+     * would require immediate replenishment upon each steal to
+     * maintain enough tasks, which is infeasible.  Further,
+     * partitionings/granularities of offered tasks should minimize
+     * steal rates, which in general means that threads nearer the top
+     * of computation tree should generate more than those nearer the
+     * bottom. In perfect steady state, each thread is at
+     * approximately the same level of computation tree. However,
+     * producing extra tasks amortizes the uncertainty of progress and
+     * diffusion assumptions.
+     *
+     * So, users will want to use values larger, but not much larger
+     * than 1 to both smooth over transient shortages and hedge
+     * against uneven progress; as traded off against the cost of
+     * extra task overhead. We leave the user to pick a threshold
+     * value to compare with the results of this call to guide
+     * decisions, but recommend values such as 3.
+     *
+     * When all threads are active, it is on average OK to estimate
+     * surplus strictly locally. In steady-state, if one thread is
+     * maintaining say 2 surplus tasks, then so are others. So we can
+     * just use estimated queue length (although note that (queueTop -
+     * queueBase) can be an overestimate because of stealers lagging
+     * increments of queueBase).  However, this strategy alone leads
+     * to serious mis-estimates in some non-steady-state conditions
+     * (ramp-up, ramp-down, other stalls). We can detect many of these
+     * by further considering the number of "idle" threads, that are
+     * known to have zero queued tasks, so compensate by a factor of
+     * (#idle/#active) threads.
+     */
+    final int getEstimatedSurplusTaskCount() {
+        return queueTop - queueBase - pool.idlePerActive();
+    }
+
+    /**
+     * Runs tasks until {@code pool.isQuiescent()}. We piggyback on
+     * pool's active count ctl maintenance, but rather than blocking
+     * when tasks cannot be found, we rescan until all others cannot
+     * find tasks either. The bracketing by pool quiescerCounts
+     * updates suppresses pool auto-shutdown mechanics that could
+     * otherwise prematurely terminate the pool because all threads
+     * appear to be inactive.
+     */
+    final void helpQuiescePool() {
+        boolean active = true;
+        ForkJoinTask<?> ps = currentSteal; // to restore below
+        ForkJoinPool p = pool;
+        p.addQuiescerCount(1);
+        for (;;) {
+            ForkJoinWorkerThread[] ws = p.workers;
+            ForkJoinWorkerThread v = null;
+            int n;
+            if (queueTop != queueBase)
+                v = this;
+            else if (ws != null && (n = ws.length) > 1) {
+                ForkJoinWorkerThread w;
+                int r = nextSeed(); // cheap version of FJP.scan
+                int steps = n << 1;
+                for (int i = 0; i < steps; ++i) {
+                    if ((w = ws[(i + r) & (n - 1)]) != null &&
+                        w.queueBase != w.queueTop) {
+                        v = w;
+                        break;
+                    }
+                }
+            }
+            if (v != null) {
+                ForkJoinTask<?> t;
+                if (!active) {
+                    active = true;
+                    p.addActiveCount(1);
+                }
+                if ((t = (v != this) ? v.deqTask() :
+                     locallyFifo ? locallyDeqTask() : popTask()) != null) {
+                    currentSteal = t;
+                    t.doExec();
+                    currentSteal = ps;
+                }
+            }
+            else {
+                if (active) {
+                    active = false;
+                    p.addActiveCount(-1);
+                }
+                if (p.isQuiescent()) {
+                    p.addActiveCount(1);
+                    p.addQuiescerCount(-1);
+                    break;
+                }
+            }
+        }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long ABASE;
+    private static final int ASHIFT;
+
+    static {
+        int s;
+        try {
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> a = ForkJoinTask[].class;
+            ABASE = UNSAFE.arrayBaseOffset(a);
+            s = UNSAFE.arrayIndexScale(a);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+        if ((s & (s-1)) != 0)
+            throw new Error("data type scale not a power of two");
+        ASHIFT = 31 - Integer.numberOfLeadingZeros(s);
+    }
+
+}
diff --git a/luni/src/main/java/java/util/concurrent/Future.java b/luni/src/main/java/java/util/concurrent/Future.java
index eb84796..6a37729 100644
--- a/luni/src/main/java/java/util/concurrent/Future.java
+++ b/luni/src/main/java/java/util/concurrent/Future.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/FutureTask.java b/luni/src/main/java/java/util/concurrent/FutureTask.java
index 2f2335e..d51881d 100644
--- a/luni/src/main/java/java/util/concurrent/FutureTask.java
+++ b/luni/src/main/java/java/util/concurrent/FutureTask.java
@@ -1,55 +1,116 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
-import java.util.concurrent.locks.*;
+import java.util.concurrent.locks.LockSupport;
 
 /**
  * A cancellable asynchronous computation.  This class provides a base
  * implementation of {@link Future}, with methods to start and cancel
  * a computation, query to see if the computation is complete, and
  * retrieve the result of the computation.  The result can only be
- * retrieved when the computation has completed; the <tt>get</tt>
- * method will block if the computation has not yet completed.  Once
+ * retrieved when the computation has completed; the {@code get}
+ * methods will block if the computation has not yet completed.  Once
  * the computation has completed, the computation cannot be restarted
- * or cancelled.
+ * or cancelled (unless the computation is invoked using
+ * {@link #runAndReset}).
  *
- * <p>A <tt>FutureTask</tt> can be used to wrap a {@link Callable} or
- * {@link java.lang.Runnable} object.  Because <tt>FutureTask</tt>
- * implements <tt>Runnable</tt>, a <tt>FutureTask</tt> can be
- * submitted to an {@link Executor} for execution.
+ * <p>A {@code FutureTask} can be used to wrap a {@link Callable} or
+ * {@link Runnable} object.  Because {@code FutureTask} implements
+ * {@code Runnable}, a {@code FutureTask} can be submitted to an
+ * {@link Executor} for execution.
  *
  * <p>In addition to serving as a standalone class, this class provides
- * <tt>protected</tt> functionality that may be useful when creating
+ * {@code protected} functionality that may be useful when creating
  * customized task classes.
  *
  * @since 1.5
  * @author Doug Lea
- * @param <V> The result type returned by this FutureTask's <tt>get</tt> method
+ * @param <V> The result type returned by this FutureTask's {@code get} methods
  */
 public class FutureTask<V> implements RunnableFuture<V> {
-    /** Synchronization control for FutureTask */
-    private final Sync sync;
+    /*
+     * Revision notes: This differs from previous versions of this
+     * class that relied on AbstractQueuedSynchronizer, mainly to
+     * avoid surprising users about retaining interrupt status during
+     * cancellation races. Sync control in the current design relies
+     * on a "state" field updated via CAS to track completion, along
+     * with a simple Treiber stack to hold waiting threads.
+     *
+     * Style note: As usual, we bypass overhead of using
+     * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
+     */
 
     /**
-     * Creates a <tt>FutureTask</tt> that will, upon running, execute the
-     * given <tt>Callable</tt>.
+     * The run state of this task, initially NEW.  The run state
+     * transitions to a terminal state only in methods set,
+     * setException, and cancel.  During completion, state may take on
+     * transient values of COMPLETING (while outcome is being set) or
+     * INTERRUPTING (only while interrupting the runner to satisfy a
+     * cancel(true)). Transitions from these intermediate to final
+     * states use cheaper ordered/lazy writes because values are unique
+     * and cannot be further modified.
+     *
+     * Possible state transitions:
+     * NEW -> COMPLETING -> NORMAL
+     * NEW -> COMPLETING -> EXCEPTIONAL
+     * NEW -> CANCELLED
+     * NEW -> INTERRUPTING -> INTERRUPTED
+     */
+    private volatile int state;
+    private static final int NEW          = 0;
+    private static final int COMPLETING   = 1;
+    private static final int NORMAL       = 2;
+    private static final int EXCEPTIONAL  = 3;
+    private static final int CANCELLED    = 4;
+    private static final int INTERRUPTING = 5;
+    private static final int INTERRUPTED  = 6;
+
+    /** The underlying callable; nulled out after running */
+    private Callable<V> callable;
+    /** The result to return or exception to throw from get() */
+    private Object outcome; // non-volatile, protected by state reads/writes
+    /** The thread running the callable; CASed during run() */
+    private volatile Thread runner;
+    /** Treiber stack of waiting threads */
+    private volatile WaitNode waiters;
+
+    /**
+     * Returns result or throws exception for completed task.
+     *
+     * @param s completed state value
+     */
+    private V report(int s) throws ExecutionException {
+        Object x = outcome;
+        if (s == NORMAL) {
+            @SuppressWarnings("unchecked") V v = (V)x;
+            return v;
+        }
+        if (s >= CANCELLED)
+            throw new CancellationException();
+        throw new ExecutionException((Throwable)x);
+    }
+
+    /**
+     * Creates a {@code FutureTask} that will, upon running, execute the
+     * given {@code Callable}.
      *
      * @param  callable the callable task
-     * @throws NullPointerException if callable is null
+     * @throws NullPointerException if the callable is null
      */
     public FutureTask(Callable<V> callable) {
         if (callable == null)
             throw new NullPointerException();
-        sync = new Sync(callable);
+        this.callable = callable;
+        this.state = NEW;       // ensure visibility of callable
     }
 
     /**
-     * Creates a <tt>FutureTask</tt> that will, upon running, execute the
-     * given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the
+     * Creates a {@code FutureTask} that will, upon running, execute the
+     * given {@code Runnable}, and arrange that {@code get} will return the
      * given result on successful completion.
      *
      * @param runnable the runnable task
@@ -57,29 +118,46 @@
      * you don't need a particular result, consider using
      * constructions of the form:
      * {@code Future<?> f = new FutureTask<Void>(runnable, null)}
-     * @throws NullPointerException if runnable is null
+     * @throws NullPointerException if the runnable is null
      */
     public FutureTask(Runnable runnable, V result) {
-        sync = new Sync(Executors.callable(runnable, result));
+        this.callable = Executors.callable(runnable, result);
+        this.state = NEW;       // ensure visibility of callable
     }
 
     public boolean isCancelled() {
-        return sync.innerIsCancelled();
+        return state >= CANCELLED;
     }
 
     public boolean isDone() {
-        return sync.innerIsDone();
+        return state != NEW;
     }
 
     public boolean cancel(boolean mayInterruptIfRunning) {
-        return sync.innerCancel(mayInterruptIfRunning);
+        if (state != NEW)
+            return false;
+        if (mayInterruptIfRunning) {
+            if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, INTERRUPTING))
+                return false;
+            Thread t = runner;
+            if (t != null)
+                t.interrupt();
+            UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // final state
+        }
+        else if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED))
+            return false;
+        finishCompletion();
+        return true;
     }
 
     /**
      * @throws CancellationException {@inheritDoc}
      */
     public V get() throws InterruptedException, ExecutionException {
-        return sync.innerGet();
+        int s = state;
+        if (s <= COMPLETING)
+            s = awaitDone(false, 0L);
+        return report(s);
     }
 
     /**
@@ -87,12 +165,18 @@
      */
     public V get(long timeout, TimeUnit unit)
         throws InterruptedException, ExecutionException, TimeoutException {
-        return sync.innerGet(unit.toNanos(timeout));
+        if (unit == null)
+            throw new NullPointerException();
+        int s = state;
+        if (s <= COMPLETING &&
+            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
+            throw new TimeoutException();
+        return report(s);
     }
 
     /**
      * Protected method invoked when this task transitions to state
-     * <tt>isDone</tt> (whether normally or via cancellation). The
+     * {@code isDone} (whether normally or via cancellation). The
      * default implementation does nothing.  Subclasses may override
      * this method to invoke completion callbacks or perform
      * bookkeeping. Note that you can query status inside the
@@ -102,230 +186,268 @@
     protected void done() { }
 
     /**
-     * Sets the result of this Future to the given value unless
+     * Sets the result of this future to the given value unless
      * this future has already been set or has been cancelled.
-     * This method is invoked internally by the <tt>run</tt> method
+     *
+     * <p>This method is invoked internally by the {@link #run} method
      * upon successful completion of the computation.
+     *
      * @param v the value
      */
     protected void set(V v) {
-        sync.innerSet(v);
+        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
+            outcome = v;
+            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
+            finishCompletion();
+        }
     }
 
     /**
-     * Causes this future to report an <tt>ExecutionException</tt>
-     * with the given throwable as its cause, unless this Future has
+     * Causes this future to report an {@link ExecutionException}
+     * with the given throwable as its cause, unless this future has
      * already been set or has been cancelled.
-     * This method is invoked internally by the <tt>run</tt> method
+     *
+     * <p>This method is invoked internally by the {@link #run} method
      * upon failure of the computation.
+     *
      * @param t the cause of failure
      */
     protected void setException(Throwable t) {
-        sync.innerSetException(t);
+        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
+            outcome = t;
+            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
+            finishCompletion();
+        }
     }
 
-    // The following (duplicated) doc comment can be removed once
-    //
-    // 6270645: Javadoc comments should be inherited from most derived
-    //          superinterface or superclass
-    // is fixed.
-    /**
-     * Sets this Future to the result of its computation
-     * unless it has been cancelled.
-     */
     public void run() {
-        sync.innerRun();
+        if (state != NEW ||
+            !UNSAFE.compareAndSwapObject(this, runnerOffset,
+                                         null, Thread.currentThread()))
+            return;
+        try {
+            Callable<V> c = callable;
+            if (c != null && state == NEW) {
+                V result;
+                boolean ran;
+                try {
+                    result = c.call();
+                    ran = true;
+                } catch (Throwable ex) {
+                    result = null;
+                    ran = false;
+                    setException(ex);
+                }
+                if (ran)
+                    set(result);
+            }
+        } finally {
+            // runner must be non-null until state is settled to
+            // prevent concurrent calls to run()
+            runner = null;
+            // state must be re-read after nulling runner to prevent
+            // leaked interrupts
+            int s = state;
+            if (s >= INTERRUPTING)
+                handlePossibleCancellationInterrupt(s);
+        }
     }
 
     /**
      * Executes the computation without setting its result, and then
-     * resets this Future to initial state, failing to do so if the
+     * resets this future to initial state, failing to do so if the
      * computation encounters an exception or is cancelled.  This is
      * designed for use with tasks that intrinsically execute more
      * than once.
+     *
      * @return true if successfully run and reset
      */
     protected boolean runAndReset() {
-        return sync.innerRunAndReset();
+        if (state != NEW ||
+            !UNSAFE.compareAndSwapObject(this, runnerOffset,
+                                         null, Thread.currentThread()))
+            return false;
+        boolean ran = false;
+        int s = state;
+        try {
+            Callable<V> c = callable;
+            if (c != null && s == NEW) {
+                try {
+                    c.call(); // don't set result
+                    ran = true;
+                } catch (Throwable ex) {
+                    setException(ex);
+                }
+            }
+        } finally {
+            // runner must be non-null until state is settled to
+            // prevent concurrent calls to run()
+            runner = null;
+            // state must be re-read after nulling runner to prevent
+            // leaked interrupts
+            s = state;
+            if (s >= INTERRUPTING)
+                handlePossibleCancellationInterrupt(s);
+        }
+        return ran && s == NEW;
     }
 
     /**
-     * Synchronization control for FutureTask. Note that this must be
-     * a non-static inner class in order to invoke the protected
-     * <tt>done</tt> method. For clarity, all inner class support
-     * methods are same as outer, prefixed with "inner".
-     *
-     * Uses AQS sync state to represent run status
+     * Ensures that any interrupt from a possible cancel(true) is only
+     * delivered to a task while in run or runAndReset.
      */
-    private final class Sync extends AbstractQueuedSynchronizer {
-        private static final long serialVersionUID = -7828117401763700385L;
+    private void handlePossibleCancellationInterrupt(int s) {
+        // It is possible for our interrupter to stall before getting a
+        // chance to interrupt us.  Let's spin-wait patiently.
+        if (s == INTERRUPTING)
+            while (state == INTERRUPTING)
+                Thread.yield(); // wait out pending interrupt
 
-        /** State value representing that task is ready to run */
-        private static final int READY     = 0;
-        /** State value representing that task is running */
-        private static final int RUNNING   = 1;
-        /** State value representing that task ran */
-        private static final int RAN       = 2;
-        /** State value representing that task was cancelled */
-        private static final int CANCELLED = 4;
+        // assert state == INTERRUPTED;
 
-        /** The underlying callable */
-        private final Callable<V> callable;
-        /** The result to return from get() */
-        private V result;
-        /** The exception to throw from get() */
-        private Throwable exception;
+        // We want to clear any interrupt we may have received from
+        // cancel(true).  However, it is permissible to use interrupts
+        // as an independent mechanism for a task to communicate with
+        // its caller, and there is no way to clear only the
+        // cancellation interrupt.
+        //
+        // Thread.interrupted();
+    }
 
-        /**
-         * The thread running task. When nulled after set/cancel, this
-         * indicates that the results are accessible.  Must be
-         * volatile, to ensure visibility upon completion.
-         */
-        private volatile Thread runner;
+    /**
+     * Simple linked list nodes to record waiting threads in a Treiber
+     * stack.  See other classes such as Phaser and SynchronousQueue
+     * for more detailed explanation.
+     */
+    static final class WaitNode {
+        volatile Thread thread;
+        volatile WaitNode next;
+        WaitNode() { thread = Thread.currentThread(); }
+    }
 
-        Sync(Callable<V> callable) {
-            this.callable = callable;
-        }
-
-        private boolean ranOrCancelled(int state) {
-            return (state & (RAN | CANCELLED)) != 0;
-        }
-
-        /**
-         * Implements AQS base acquire to succeed if ran or cancelled
-         */
-        protected int tryAcquireShared(int ignore) {
-            return innerIsDone() ? 1 : -1;
-        }
-
-        /**
-         * Implements AQS base release to always signal after setting
-         * final done status by nulling runner thread.
-         */
-        protected boolean tryReleaseShared(int ignore) {
-            runner = null;
-            return true;
-        }
-
-        boolean innerIsCancelled() {
-            return getState() == CANCELLED;
-        }
-
-        boolean innerIsDone() {
-            return ranOrCancelled(getState()) && runner == null;
-        }
-
-        V innerGet() throws InterruptedException, ExecutionException {
-            acquireSharedInterruptibly(0);
-            if (getState() == CANCELLED)
-                throw new CancellationException();
-            if (exception != null)
-                throw new ExecutionException(exception);
-            return result;
-        }
-
-        V innerGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
-            if (!tryAcquireSharedNanos(0, nanosTimeout))
-                throw new TimeoutException();
-            if (getState() == CANCELLED)
-                throw new CancellationException();
-            if (exception != null)
-                throw new ExecutionException(exception);
-            return result;
-        }
-
-        void innerSet(V v) {
-            for (;;) {
-                int s = getState();
-                if (s == RAN)
-                    return;
-                if (s == CANCELLED) {
-                    // aggressively release to set runner to null,
-                    // in case we are racing with a cancel request
-                    // that will try to interrupt runner
-                    releaseShared(0);
-                    return;
+    /**
+     * Removes and signals all waiting threads, invokes done(), and
+     * nulls out callable.
+     */
+    private void finishCompletion() {
+        // assert state > COMPLETING;
+        for (WaitNode q; (q = waiters) != null;) {
+            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
+                for (;;) {
+                    Thread t = q.thread;
+                    if (t != null) {
+                        q.thread = null;
+                        LockSupport.unpark(t);
+                    }
+                    WaitNode next = q.next;
+                    if (next == null)
+                        break;
+                    q.next = null; // unlink to help gc
+                    q = next;
                 }
-                if (compareAndSetState(s, RAN)) {
-                    result = v;
-                    releaseShared(0);
-                    done();
-                    return;
-                }
+                break;
             }
         }
 
-        void innerSetException(Throwable t) {
-            for (;;) {
-                int s = getState();
-                if (s == RAN)
-                    return;
-                if (s == CANCELLED) {
-                    // aggressively release to set runner to null,
-                    // in case we are racing with a cancel request
-                    // that will try to interrupt runner
-                    releaseShared(0);
-                    return;
+        done();
+
+        callable = null;        // to reduce footprint
+    }
+
+    /**
+     * Awaits completion or aborts on interrupt or timeout.
+     *
+     * @param timed true if use timed waits
+     * @param nanos time to wait, if timed
+     * @return state upon completion
+     */
+    private int awaitDone(boolean timed, long nanos)
+        throws InterruptedException {
+        long last = timed ? System.nanoTime() : 0L;
+        WaitNode q = null;
+        boolean queued = false;
+        for (;;) {
+            if (Thread.interrupted()) {
+                removeWaiter(q);
+                throw new InterruptedException();
+            }
+
+            int s = state;
+            if (s > COMPLETING) {
+                if (q != null)
+                    q.thread = null;
+                return s;
+            }
+            else if (q == null)
+                q = new WaitNode();
+            else if (!queued)
+                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
+                                                     q.next = waiters, q);
+            else if (timed) {
+                long now = System.nanoTime();
+                if ((nanos -= (now - last)) <= 0L) {
+                    removeWaiter(q);
+                    return state;
                 }
-                if (compareAndSetState(s, RAN)) {
-                    exception = t;
-                    releaseShared(0);
-                    done();
-                    return;
+                last = now;
+                LockSupport.parkNanos(this, nanos);
+            }
+            else
+                LockSupport.park(this);
+        }
+    }
+
+    /**
+     * Tries to unlink a timed-out or interrupted wait node to avoid
+     * accumulating garbage.  Internal nodes are simply unspliced
+     * without CAS since it is harmless if they are traversed anyway
+     * by releasers.  To avoid effects of unsplicing from already
+     * removed nodes, the list is retraversed in case of an apparent
+     * race.  This is slow when there are a lot of nodes, but we don't
+     * expect lists to be long enough to outweigh higher-overhead
+     * schemes.
+     */
+    private void removeWaiter(WaitNode node) {
+        if (node != null) {
+            node.thread = null;
+            retry:
+            for (;;) {          // restart on removeWaiter race
+                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
+                    s = q.next;
+                    if (q.thread != null)
+                        pred = q;
+                    else if (pred != null) {
+                        pred.next = s;
+                        if (pred.thread == null) // check for race
+                            continue retry;
+                    }
+                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
+                                                          q, s))
+                        continue retry;
                 }
-            }
-        }
-
-        boolean innerCancel(boolean mayInterruptIfRunning) {
-            for (;;) {
-                int s = getState();
-                if (ranOrCancelled(s))
-                    return false;
-                if (compareAndSetState(s, CANCELLED))
-                    break;
-            }
-            if (mayInterruptIfRunning) {
-                Thread r = runner;
-                if (r != null)
-                    r.interrupt();
-            }
-            releaseShared(0);
-            done();
-            return true;
-        }
-
-        void innerRun() {
-            if (!compareAndSetState(READY, RUNNING))
-                return;
-
-            runner = Thread.currentThread();
-            if (getState() == RUNNING) { // recheck after setting thread
-                V result;
-                try {
-                    result = callable.call();
-                } catch (Throwable ex) {
-                    setException(ex);
-                    return;
-                }
-                set(result);
-            } else {
-                releaseShared(0); // cancel
-            }
-        }
-
-        boolean innerRunAndReset() {
-            if (!compareAndSetState(READY, RUNNING))
-                return false;
-            try {
-                runner = Thread.currentThread();
-                if (getState() == RUNNING)
-                    callable.call(); // don't set result
-                runner = null;
-                return compareAndSetState(RUNNING, READY);
-            } catch (Throwable ex) {
-                setException(ex);
-                return false;
+                break;
             }
         }
     }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long stateOffset;
+    private static final long runnerOffset;
+    private static final long waitersOffset;
+    static {
+        try {
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = FutureTask.class;
+            stateOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("state"));
+            runnerOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("runner"));
+            waitersOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("waiters"));
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+
 }
diff --git a/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java b/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
index 8c01e71..6f32c47 100644
--- a/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
+++ b/luni/src/main/java/java/util/concurrent/LinkedBlockingDeque.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -13,6 +13,10 @@
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
 
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
 /**
  * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
  * linked nodes.
@@ -34,10 +38,6 @@
  * <em>optional</em> methods of the {@link Collection} and {@link
  * Iterator} interfaces.
  *
- * <p>This class is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
- * Java Collections Framework</a>.
- *
  * @since 1.6
  * @author  Doug Lea
  * @param <E> the type of elements held in this collection
@@ -590,7 +590,7 @@
     /**
      * Inserts the specified element at the end of this deque unless it would
      * violate capacity restrictions.  When using a capacity-restricted deque,
-     * it is generally preferable to use method {@link #offer offer}.
+     * it is generally preferable to use method {@link #offer(Object) offer}.
      *
      * <p>This method is equivalent to {@link #addLast}.
      *
@@ -713,6 +713,8 @@
             throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
@@ -891,8 +893,7 @@
      * The following code can be used to dump the deque into a newly
      * allocated array of {@code String}:
      *
-     * <pre>
-     *     String[] y = x.toArray(new String[0]);</pre>
+     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
      *
      * Note that {@code toArray(new Object[0])} is identical in function to
      * {@code toArray()}.
@@ -1014,7 +1015,7 @@
         /**
          * The next node to return in next()
          */
-         Node<E> next;
+        Node<E> next;
 
         /**
          * nextItem holds on to item fields because once we claim that
@@ -1122,7 +1123,7 @@
     }
 
     /**
-     * Save the state of this deque to a stream (that is, serialize it).
+     * Saves the state of this deque to a stream (that is, serializes it).
      *
      * @serialData The capacity (int), followed by elements (each an
      * {@code Object}) in the proper order, followed by a null
@@ -1146,8 +1147,8 @@
     }
 
     /**
-     * Reconstitute this deque from a stream (that is,
-     * deserialize it).
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     *
      * @param s the stream
      */
     private void readObject(java.io.ObjectInputStream s)
diff --git a/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java b/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
index d06c737..e8c9edb 100644
--- a/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/LinkedBlockingQueue.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -106,13 +106,13 @@
     private final int capacity;
 
     /** Current number of elements */
-    private final AtomicInteger count = new AtomicInteger(0);
+    private final AtomicInteger count = new AtomicInteger();
 
     /**
      * Head of linked list.
      * Invariant: head.item == null
      */
-    private transient Node<E> head;
+    transient Node<E> head;
 
     /**
      * Tail of linked list.
@@ -303,7 +303,7 @@
         // Note: convention in all put/take/etc is to preset local var
         // holding count negative to indicate failure unless set.
         int c = -1;
-        Node<E> node = new Node(e);
+        Node<E> node = new Node<E>(e);
         final ReentrantLock putLock = this.putLock;
         final AtomicInteger count = this.count;
         putLock.lockInterruptibly();
@@ -383,7 +383,7 @@
         if (count.get() == capacity)
             return false;
         int c = -1;
-        Node<E> node = new Node(e);
+        Node<E> node = new Node<E>(e);
         final ReentrantLock putLock = this.putLock;
         putLock.lock();
         try {
@@ -601,8 +601,7 @@
      * The following code can be used to dump the queue into a newly
      * allocated array of {@code String}:
      *
-     * <pre>
-     *     String[] y = x.toArray(new String[0]);</pre>
+     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
      *
      * Note that {@code toArray(new Object[0])} is identical in function to
      * {@code toArray()}.
@@ -699,6 +698,8 @@
             throw new NullPointerException();
         if (c == this)
             throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
         boolean signalNotFull = false;
         final ReentrantLock takeLock = this.takeLock;
         takeLock.lock();
@@ -746,7 +747,7 @@
      * @return an iterator over the elements in this queue in proper sequence
      */
     public Iterator<E> iterator() {
-      return new Itr();
+        return new Itr();
     }
 
     private class Itr implements Iterator<E> {
@@ -829,7 +830,7 @@
     }
 
     /**
-     * Save the state to a stream (that is, serialize it).
+     * Saves the state to a stream (that is, serializes it).
      *
      * @serialData The capacity is emitted (int), followed by all of
      * its elements (each an {@code Object}) in the proper order,
@@ -856,8 +857,7 @@
     }
 
     /**
-     * Reconstitute this queue instance from a stream (that is,
-     * deserialize it).
+     * Reconstitutes this queue from a stream (that is, deserializes it).
      *
      * @param s the stream
      */
diff --git a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
new file mode 100644
index 0000000..2a3446e
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
@@ -0,0 +1,1323 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.LockSupport;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded {@link TransferQueue} based on linked nodes.
+ * This queue orders elements FIFO (first-in-first-out) with respect
+ * to any given producer.  The <em>head</em> of the queue is that
+ * element that has been on the queue the longest time for some
+ * producer.  The <em>tail</em> of the queue is that element that has
+ * been on the queue the shortest time for some producer.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size} method
+ * is <em>NOT</em> a constant-time operation. Because of the
+ * asynchronous nature of these queues, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code LinkedTransferQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code LinkedTransferQueue} in another thread.
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ * @param <E> the type of elements held in this collection
+ */
+public class LinkedTransferQueue<E> extends AbstractQueue<E>
+    implements TransferQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = -3223113410248163686L;
+
+    /*
+     * *** Overview of Dual Queues with Slack ***
+     *
+     * Dual Queues, introduced by Scherer and Scott
+     * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are
+     * (linked) queues in which nodes may represent either data or
+     * requests.  When a thread tries to enqueue a data node, but
+     * encounters a request node, it instead "matches" and removes it;
+     * and vice versa for enqueuing requests. Blocking Dual Queues
+     * arrange that threads enqueuing unmatched requests block until
+     * other threads provide the match. Dual Synchronous Queues (see
+     * Scherer, Lea, & Scott
+     * http://www.cs.rochester.edu/u/scott/papers/2009_Scherer_CACM_SSQ.pdf)
+     * additionally arrange that threads enqueuing unmatched data also
+     * block.  Dual Transfer Queues support all of these modes, as
+     * dictated by callers.
+     *
+     * A FIFO dual queue may be implemented using a variation of the
+     * Michael & Scott (M&S) lock-free queue algorithm
+     * (http://www.cs.rochester.edu/u/scott/papers/1996_PODC_queues.pdf).
+     * It maintains two pointer fields, "head", pointing to a
+     * (matched) node that in turn points to the first actual
+     * (unmatched) queue node (or null if empty); and "tail" that
+     * points to the last node on the queue (or again null if
+     * empty). For example, here is a possible queue with four data
+     * elements:
+     *
+     *  head                tail
+     *    |                   |
+     *    v                   v
+     *    M -> U -> U -> U -> U
+     *
+     * The M&S queue algorithm is known to be prone to scalability and
+     * overhead limitations when maintaining (via CAS) these head and
+     * tail pointers. This has led to the development of
+     * contention-reducing variants such as elimination arrays (see
+     * Moir et al http://portal.acm.org/citation.cfm?id=1074013) and
+     * optimistic back pointers (see Ladan-Mozes & Shavit
+     * http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf).
+     * However, the nature of dual queues enables a simpler tactic for
+     * improving M&S-style implementations when dual-ness is needed.
+     *
+     * In a dual queue, each node must atomically maintain its match
+     * status. While there are other possible variants, we implement
+     * this here as: for a data-mode node, matching entails CASing an
+     * "item" field from a non-null data value to null upon match, and
+     * vice-versa for request nodes, CASing from null to a data
+     * value. (Note that the linearization properties of this style of
+     * queue are easy to verify -- elements are made available by
+     * linking, and unavailable by matching.) Compared to plain M&S
+     * queues, this property of dual queues requires one additional
+     * successful atomic operation per enq/deq pair. But it also
+     * enables lower cost variants of queue maintenance mechanics. (A
+     * variation of this idea applies even for non-dual queues that
+     * support deletion of interior elements, such as
+     * j.u.c.ConcurrentLinkedQueue.)
+     *
+     * Once a node is matched, its match status can never again
+     * change.  We may thus arrange that the linked list of them
+     * contain a prefix of zero or more matched nodes, followed by a
+     * suffix of zero or more unmatched nodes. (Note that we allow
+     * both the prefix and suffix to be zero length, which in turn
+     * means that we do not use a dummy header.)  If we were not
+     * concerned with either time or space efficiency, we could
+     * correctly perform enqueue and dequeue operations by traversing
+     * from a pointer to the initial node; CASing the item of the
+     * first unmatched node on match and CASing the next field of the
+     * trailing node on appends. (Plus some special-casing when
+     * initially empty).  While this would be a terrible idea in
+     * itself, it does have the benefit of not requiring ANY atomic
+     * updates on head/tail fields.
+     *
+     * We introduce here an approach that lies between the extremes of
+     * never versus always updating queue (head and tail) pointers.
+     * This offers a tradeoff between sometimes requiring extra
+     * traversal steps to locate the first and/or last unmatched
+     * nodes, versus the reduced overhead and contention of fewer
+     * updates to queue pointers. For example, a possible snapshot of
+     * a queue is:
+     *
+     *  head           tail
+     *    |              |
+     *    v              v
+     *    M -> M -> U -> U -> U -> U
+     *
+     * The best value for this "slack" (the targeted maximum distance
+     * between the value of "head" and the first unmatched node, and
+     * similarly for "tail") is an empirical matter. We have found
+     * that using very small constants in the range of 1-3 work best
+     * over a range of platforms. Larger values introduce increasing
+     * costs of cache misses and risks of long traversal chains, while
+     * smaller values increase CAS contention and overhead.
+     *
+     * Dual queues with slack differ from plain M&S dual queues by
+     * virtue of only sometimes updating head or tail pointers when
+     * matching, appending, or even traversing nodes; in order to
+     * maintain a targeted slack.  The idea of "sometimes" may be
+     * operationalized in several ways. The simplest is to use a
+     * per-operation counter incremented on each traversal step, and
+     * to try (via CAS) to update the associated queue pointer
+     * whenever the count exceeds a threshold. Another, that requires
+     * more overhead, is to use random number generators to update
+     * with a given probability per traversal step.
+     *
+     * In any strategy along these lines, because CASes updating
+     * fields may fail, the actual slack may exceed targeted
+     * slack. However, they may be retried at any time to maintain
+     * targets.  Even when using very small slack values, this
+     * approach works well for dual queues because it allows all
+     * operations up to the point of matching or appending an item
+     * (hence potentially allowing progress by another thread) to be
+     * read-only, thus not introducing any further contention. As
+     * described below, we implement this by performing slack
+     * maintenance retries only after these points.
+     *
+     * As an accompaniment to such techniques, traversal overhead can
+     * be further reduced without increasing contention of head
+     * pointer updates: Threads may sometimes shortcut the "next" link
+     * path from the current "head" node to be closer to the currently
+     * known first unmatched node, and similarly for tail. Again, this
+     * may be triggered with using thresholds or randomization.
+     *
+     * These ideas must be further extended to avoid unbounded amounts
+     * of costly-to-reclaim garbage caused by the sequential "next"
+     * links of nodes starting at old forgotten head nodes: As first
+     * described in detail by Boehm
+     * (http://portal.acm.org/citation.cfm?doid=503272.503282) if a GC
+     * delays noticing that any arbitrarily old node has become
+     * garbage, all newer dead nodes will also be unreclaimed.
+     * (Similar issues arise in non-GC environments.)  To cope with
+     * this in our implementation, upon CASing to advance the head
+     * pointer, we set the "next" link of the previous head to point
+     * only to itself; thus limiting the length of connected dead lists.
+     * (We also take similar care to wipe out possibly garbage
+     * retaining values held in other Node fields.)  However, doing so
+     * adds some further complexity to traversal: If any "next"
+     * pointer links to itself, it indicates that the current thread
+     * has lagged behind a head-update, and so the traversal must
+     * continue from the "head".  Traversals trying to find the
+     * current tail starting from "tail" may also encounter
+     * self-links, in which case they also continue at "head".
+     *
+     * It is tempting in slack-based scheme to not even use CAS for
+     * updates (similarly to Ladan-Mozes & Shavit). However, this
+     * cannot be done for head updates under the above link-forgetting
+     * mechanics because an update may leave head at a detached node.
+     * And while direct writes are possible for tail updates, they
+     * increase the risk of long retraversals, and hence long garbage
+     * chains, which can be much more costly than is worthwhile
+     * considering that the cost difference of performing a CAS vs
+     * write is smaller when they are not triggered on each operation
+     * (especially considering that writes and CASes equally require
+     * additional GC bookkeeping ("write barriers") that are sometimes
+     * more costly than the writes themselves because of contention).
+     *
+     * *** Overview of implementation ***
+     *
+     * We use a threshold-based approach to updates, with a slack
+     * threshold of two -- that is, we update head/tail when the
+     * current pointer appears to be two or more steps away from the
+     * first/last node. The slack value is hard-wired: a path greater
+     * than one is naturally implemented by checking equality of
+     * traversal pointers except when the list has only one element,
+     * in which case we keep slack threshold at one. Avoiding tracking
+     * explicit counts across method calls slightly simplifies an
+     * already-messy implementation. Using randomization would
+     * probably work better if there were a low-quality dirt-cheap
+     * per-thread one available, but even ThreadLocalRandom is too
+     * heavy for these purposes.
+     *
+     * With such a small slack threshold value, it is not worthwhile
+     * to augment this with path short-circuiting (i.e., unsplicing
+     * interior nodes) except in the case of cancellation/removal (see
+     * below).
+     *
+     * We allow both the head and tail fields to be null before any
+     * nodes are enqueued; initializing upon first append.  This
+     * simplifies some other logic, as well as providing more
+     * efficient explicit control paths instead of letting JVMs insert
+     * implicit NullPointerExceptions when they are null.  While not
+     * currently fully implemented, we also leave open the possibility
+     * of re-nulling these fields when empty (which is complicated to
+     * arrange, for little benefit.)
+     *
+     * All enqueue/dequeue operations are handled by the single method
+     * "xfer" with parameters indicating whether to act as some form
+     * of offer, put, poll, take, or transfer (each possibly with
+     * timeout). The relative complexity of using one monolithic
+     * method outweighs the code bulk and maintenance problems of
+     * using separate methods for each case.
+     *
+     * Operation consists of up to three phases. The first is
+     * implemented within method xfer, the second in tryAppend, and
+     * the third in method awaitMatch.
+     *
+     * 1. Try to match an existing node
+     *
+     *    Starting at head, skip already-matched nodes until finding
+     *    an unmatched node of opposite mode, if one exists, in which
+     *    case matching it and returning, also if necessary updating
+     *    head to one past the matched node (or the node itself if the
+     *    list has no other unmatched nodes). If the CAS misses, then
+     *    a loop retries advancing head by two steps until either
+     *    success or the slack is at most two. By requiring that each
+     *    attempt advances head by two (if applicable), we ensure that
+     *    the slack does not grow without bound. Traversals also check
+     *    if the initial head is now off-list, in which case they
+     *    start at the new head.
+     *
+     *    If no candidates are found and the call was untimed
+     *    poll/offer, (argument "how" is NOW) return.
+     *
+     * 2. Try to append a new node (method tryAppend)
+     *
+     *    Starting at current tail pointer, find the actual last node
+     *    and try to append a new node (or if head was null, establish
+     *    the first node). Nodes can be appended only if their
+     *    predecessors are either already matched or are of the same
+     *    mode. If we detect otherwise, then a new node with opposite
+     *    mode must have been appended during traversal, so we must
+     *    restart at phase 1. The traversal and update steps are
+     *    otherwise similar to phase 1: Retrying upon CAS misses and
+     *    checking for staleness.  In particular, if a self-link is
+     *    encountered, then we can safely jump to a node on the list
+     *    by continuing the traversal at current head.
+     *
+     *    On successful append, if the call was ASYNC, return.
+     *
+     * 3. Await match or cancellation (method awaitMatch)
+     *
+     *    Wait for another thread to match node; instead cancelling if
+     *    the current thread was interrupted or the wait timed out. On
+     *    multiprocessors, we use front-of-queue spinning: If a node
+     *    appears to be the first unmatched node in the queue, it
+     *    spins a bit before blocking. In either case, before blocking
+     *    it tries to unsplice any nodes between the current "head"
+     *    and the first unmatched node.
+     *
+     *    Front-of-queue spinning vastly improves performance of
+     *    heavily contended queues. And so long as it is relatively
+     *    brief and "quiet", spinning does not much impact performance
+     *    of less-contended queues.  During spins threads check their
+     *    interrupt status and generate a thread-local random number
+     *    to decide to occasionally perform a Thread.yield. While
+     *    yield has underdefined specs, we assume that it might help,
+     *    and will not hurt, in limiting impact of spinning on busy
+     *    systems.  We also use smaller (1/2) spins for nodes that are
+     *    not known to be front but whose predecessors have not
+     *    blocked -- these "chained" spins avoid artifacts of
+     *    front-of-queue rules which otherwise lead to alternating
+     *    nodes spinning vs blocking. Further, front threads that
+     *    represent phase changes (from data to request node or vice
+     *    versa) compared to their predecessors receive additional
+     *    chained spins, reflecting longer paths typically required to
+     *    unblock threads during phase changes.
+     *
+     *
+     * ** Unlinking removed interior nodes **
+     *
+     * In addition to minimizing garbage retention via self-linking
+     * described above, we also unlink removed interior nodes. These
+     * may arise due to timed out or interrupted waits, or calls to
+     * remove(x) or Iterator.remove.  Normally, given a node that was
+     * at one time known to be the predecessor of some node s that is
+     * to be removed, we can unsplice s by CASing the next field of
+     * its predecessor if it still points to s (otherwise s must
+     * already have been removed or is now offlist). But there are two
+     * situations in which we cannot guarantee to make node s
+     * unreachable in this way: (1) If s is the trailing node of list
+     * (i.e., with null next), then it is pinned as the target node
+     * for appends, so can only be removed later after other nodes are
+     * appended. (2) We cannot necessarily unlink s given a
+     * predecessor node that is matched (including the case of being
+     * cancelled): the predecessor may already be unspliced, in which
+     * case some previous reachable node may still point to s.
+     * (For further explanation see Herlihy & Shavit "The Art of
+     * Multiprocessor Programming" chapter 9).  Although, in both
+     * cases, we can rule out the need for further action if either s
+     * or its predecessor are (or can be made to be) at, or fall off
+     * from, the head of list.
+     *
+     * Without taking these into account, it would be possible for an
+     * unbounded number of supposedly removed nodes to remain
+     * reachable.  Situations leading to such buildup are uncommon but
+     * can occur in practice; for example when a series of short timed
+     * calls to poll repeatedly time out but never otherwise fall off
+     * the list because of an untimed call to take at the front of the
+     * queue.
+     *
+     * When these cases arise, rather than always retraversing the
+     * entire list to find an actual predecessor to unlink (which
+     * won't help for case (1) anyway), we record a conservative
+     * estimate of possible unsplice failures (in "sweepVotes").
+     * We trigger a full sweep when the estimate exceeds a threshold
+     * ("SWEEP_THRESHOLD") indicating the maximum number of estimated
+     * removal failures to tolerate before sweeping through, unlinking
+     * cancelled nodes that were not unlinked upon initial removal.
+     * We perform sweeps by the thread hitting threshold (rather than
+     * background threads or by spreading work to other threads)
+     * because in the main contexts in which removal occurs, the
+     * caller is already timed-out, cancelled, or performing a
+     * potentially O(n) operation (e.g. remove(x)), none of which are
+     * time-critical enough to warrant the overhead that alternatives
+     * would impose on other threads.
+     *
+     * Because the sweepVotes estimate is conservative, and because
+     * nodes become unlinked "naturally" as they fall off the head of
+     * the queue, and because we allow votes to accumulate even while
+     * sweeps are in progress, there are typically significantly fewer
+     * such nodes than estimated.  Choice of a threshold value
+     * balances the likelihood of wasted effort and contention, versus
+     * providing a worst-case bound on retention of interior nodes in
+     * quiescent queues. The value defined below was chosen
+     * empirically to balance these under various timeout scenarios.
+     *
+     * Note that we cannot self-link unlinked interior nodes during
+     * sweeps. However, the associated garbage chains terminate when
+     * some successor ultimately falls off the head of the list and is
+     * self-linked.
+     */
+
+    /** True if on multiprocessor */
+    private static final boolean MP =
+        Runtime.getRuntime().availableProcessors() > 1;
+
+    /**
+     * The number of times to spin (with randomly interspersed calls
+     * to Thread.yield) on multiprocessor before blocking when a node
+     * is apparently the first waiter in the queue.  See above for
+     * explanation. Must be a power of two. The value is empirically
+     * derived -- it works pretty well across a variety of processors,
+     * numbers of CPUs, and OSes.
+     */
+    private static final int FRONT_SPINS   = 1 << 7;
+
+    /**
+     * The number of times to spin before blocking when a node is
+     * preceded by another node that is apparently spinning.  Also
+     * serves as an increment to FRONT_SPINS on phase changes, and as
+     * base average frequency for yielding during spins. Must be a
+     * power of two.
+     */
+    private static final int CHAINED_SPINS = FRONT_SPINS >>> 1;
+
+    /**
+     * The maximum number of estimated removal failures (sweepVotes)
+     * to tolerate before sweeping through the queue unlinking
+     * cancelled nodes that were not unlinked upon initial
+     * removal. See above for explanation. The value must be at least
+     * two to avoid useless sweeps when removing trailing nodes.
+     */
+    static final int SWEEP_THRESHOLD = 32;
+
+    /**
+     * Queue nodes. Uses Object, not E, for items to allow forgetting
+     * them after use.  Relies heavily on Unsafe mechanics to minimize
+     * unnecessary ordering constraints: Writes that are intrinsically
+     * ordered wrt other accesses or CASes use simple relaxed forms.
+     */
+    static final class Node {
+        final boolean isData;   // false if this is a request node
+        volatile Object item;   // initially non-null if isData; CASed to match
+        volatile Node next;
+        volatile Thread waiter; // null until waiting
+
+        // CAS methods for fields
+        final boolean casNext(Node cmp, Node val) {
+            return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
+        }
+
+        final boolean casItem(Object cmp, Object val) {
+            // assert cmp == null || cmp.getClass() != Node.class;
+            return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
+        }
+
+        /**
+         * Constructs a new node.  Uses relaxed write because item can
+         * only be seen after publication via casNext.
+         */
+        Node(Object item, boolean isData) {
+            UNSAFE.putObject(this, itemOffset, item); // relaxed write
+            this.isData = isData;
+        }
+
+        /**
+         * Links node to itself to avoid garbage retention.  Called
+         * only after CASing head field, so uses relaxed write.
+         */
+        final void forgetNext() {
+            UNSAFE.putObject(this, nextOffset, this);
+        }
+
+        /**
+         * Sets item to self and waiter to null, to avoid garbage
+         * retention after matching or cancelling. Uses relaxed writes
+         * because order is already constrained in the only calling
+         * contexts: item is forgotten only after volatile/atomic
+         * mechanics that extract items.  Similarly, clearing waiter
+         * follows either CAS or return from park (if ever parked;
+         * else we don't care).
+         */
+        final void forgetContents() {
+            UNSAFE.putObject(this, itemOffset, this);
+            UNSAFE.putObject(this, waiterOffset, null);
+        }
+
+        /**
+         * Returns true if this node has been matched, including the
+         * case of artificial matches due to cancellation.
+         */
+        final boolean isMatched() {
+            Object x = item;
+            return (x == this) || ((x == null) == isData);
+        }
+
+        /**
+         * Returns true if this is an unmatched request node.
+         */
+        final boolean isUnmatchedRequest() {
+            return !isData && item == null;
+        }
+
+        /**
+         * Returns true if a node with the given mode cannot be
+         * appended to this node because this node is unmatched and
+         * has opposite data mode.
+         */
+        final boolean cannotPrecede(boolean haveData) {
+            boolean d = isData;
+            Object x;
+            return d != haveData && (x = item) != this && (x != null) == d;
+        }
+
+        /**
+         * Tries to artificially match a data node -- used by remove.
+         */
+        final boolean tryMatchData() {
+            // assert isData;
+            Object x = item;
+            if (x != null && x != this && casItem(x, null)) {
+                LockSupport.unpark(waiter);
+                return true;
+            }
+            return false;
+        }
+
+        private static final long serialVersionUID = -3375979862319811754L;
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long itemOffset;
+        private static final long nextOffset;
+        private static final long waiterOffset;
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class<?> k = Node.class;
+                itemOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("item"));
+                nextOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("next"));
+                waiterOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("waiter"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /** head of the queue; null until first enqueue */
+    transient volatile Node head;
+
+    /** tail of the queue; null until first append */
+    private transient volatile Node tail;
+
+    /** The number of apparent failures to unsplice removed nodes */
+    private transient volatile int sweepVotes;
+
+    // CAS methods for fields
+    private boolean casTail(Node cmp, Node val) {
+        return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
+    }
+
+    private boolean casHead(Node cmp, Node val) {
+        return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
+    }
+
+    private boolean casSweepVotes(int cmp, int val) {
+        return UNSAFE.compareAndSwapInt(this, sweepVotesOffset, cmp, val);
+    }
+
+    /*
+     * Possible values for "how" argument in xfer method.
+     */
+    private static final int NOW   = 0; // for untimed poll, tryTransfer
+    private static final int ASYNC = 1; // for offer, put, add
+    private static final int SYNC  = 2; // for transfer, take
+    private static final int TIMED = 3; // for timed poll, tryTransfer
+
+    @SuppressWarnings("unchecked")
+    static <E> E cast(Object item) {
+        // assert item == null || item.getClass() != Node.class;
+        return (E) item;
+    }
+
+    /**
+     * Implements all queuing methods. See above for explanation.
+     *
+     * @param e the item or null for take
+     * @param haveData true if this is a put, else a take
+     * @param how NOW, ASYNC, SYNC, or TIMED
+     * @param nanos timeout in nanosecs, used only if mode is TIMED
+     * @return an item if matched, else e
+     * @throws NullPointerException if haveData mode but e is null
+     */
+    private E xfer(E e, boolean haveData, int how, long nanos) {
+        if (haveData && (e == null))
+            throw new NullPointerException();
+        Node s = null;                        // the node to append, if needed
+
+        retry:
+        for (;;) {                            // restart on append race
+
+            for (Node h = head, p = h; p != null;) { // find & match first node
+                boolean isData = p.isData;
+                Object item = p.item;
+                if (item != p && (item != null) == isData) { // unmatched
+                    if (isData == haveData)   // can't match
+                        break;
+                    if (p.casItem(item, e)) { // match
+                        for (Node q = p; q != h;) {
+                            Node n = q.next;  // update by 2 unless singleton
+                            if (head == h && casHead(h, n == null ? q : n)) {
+                                h.forgetNext();
+                                break;
+                            }                 // advance and retry
+                            if ((h = head)   == null ||
+                                (q = h.next) == null || !q.isMatched())
+                                break;        // unless slack < 2
+                        }
+                        LockSupport.unpark(p.waiter);
+                        return LinkedTransferQueue.<E>cast(item);
+                    }
+                }
+                Node n = p.next;
+                p = (p != n) ? n : (h = head); // Use head if p offlist
+            }
+
+            if (how != NOW) {                 // No matches available
+                if (s == null)
+                    s = new Node(e, haveData);
+                Node pred = tryAppend(s, haveData);
+                if (pred == null)
+                    continue retry;           // lost race vs opposite mode
+                if (how != ASYNC)
+                    return awaitMatch(s, pred, e, (how == TIMED), nanos);
+            }
+            return e; // not waiting
+        }
+    }
+
+    /**
+     * Tries to append node s as tail.
+     *
+     * @param s the node to append
+     * @param haveData true if appending in data mode
+     * @return null on failure due to losing race with append in
+     * different mode, else s's predecessor, or s itself if no
+     * predecessor
+     */
+    private Node tryAppend(Node s, boolean haveData) {
+        for (Node t = tail, p = t;;) {        // move p to last node and append
+            Node n, u;                        // temps for reads of next & tail
+            if (p == null && (p = head) == null) {
+                if (casHead(null, s))
+                    return s;                 // initialize
+            }
+            else if (p.cannotPrecede(haveData))
+                return null;                  // lost race vs opposite mode
+            else if ((n = p.next) != null)    // not last; keep traversing
+                p = p != t && t != (u = tail) ? (t = u) : // stale tail
+                    (p != n) ? n : null;      // restart if off list
+            else if (!p.casNext(null, s))
+                p = p.next;                   // re-read on CAS failure
+            else {
+                if (p != t) {                 // update if slack now >= 2
+                    while ((tail != t || !casTail(t, s)) &&
+                           (t = tail)   != null &&
+                           (s = t.next) != null && // advance and retry
+                           (s = s.next) != null && s != t);
+                }
+                return p;
+            }
+        }
+    }
+
+    /**
+     * Spins/yields/blocks until node s is matched or caller gives up.
+     *
+     * @param s the waiting node
+     * @param pred the predecessor of s, or s itself if it has no
+     * predecessor, or null if unknown (the null case does not occur
+     * in any current calls but may in possible future extensions)
+     * @param e the comparison value for checking match
+     * @param timed if true, wait only until timeout elapses
+     * @param nanos timeout in nanosecs, used only if timed is true
+     * @return matched item, or e if unmatched on interrupt or timeout
+     */
+    private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) {
+        long lastTime = timed ? System.nanoTime() : 0L;
+        Thread w = Thread.currentThread();
+        int spins = -1; // initialized after first item and cancel checks
+        ThreadLocalRandom randomYields = null; // bound if needed
+
+        for (;;) {
+            Object item = s.item;
+            if (item != e) {                  // matched
+                // assert item != s;
+                s.forgetContents();           // avoid garbage
+                return LinkedTransferQueue.<E>cast(item);
+            }
+            if ((w.isInterrupted() || (timed && nanos <= 0)) &&
+                    s.casItem(e, s)) {        // cancel
+                unsplice(pred, s);
+                return e;
+            }
+
+            if (spins < 0) {                  // establish spins at/near front
+                if ((spins = spinsFor(pred, s.isData)) > 0)
+                    randomYields = ThreadLocalRandom.current();
+            }
+            else if (spins > 0) {             // spin
+                --spins;
+                if (randomYields.nextInt(CHAINED_SPINS) == 0)
+                    Thread.yield();           // occasionally yield
+            }
+            else if (s.waiter == null) {
+                s.waiter = w;                 // request unpark then recheck
+            }
+            else if (timed) {
+                long now = System.nanoTime();
+                if ((nanos -= now - lastTime) > 0)
+                    LockSupport.parkNanos(this, nanos);
+                lastTime = now;
+            }
+            else {
+                LockSupport.park(this);
+            }
+        }
+    }
+
+    /**
+     * Returns spin/yield value for a node with given predecessor and
+     * data mode. See above for explanation.
+     */
+    private static int spinsFor(Node pred, boolean haveData) {
+        if (MP && pred != null) {
+            if (pred.isData != haveData)      // phase change
+                return FRONT_SPINS + CHAINED_SPINS;
+            if (pred.isMatched())             // probably at front
+                return FRONT_SPINS;
+            if (pred.waiter == null)          // pred apparently spinning
+                return CHAINED_SPINS;
+        }
+        return 0;
+    }
+
+    /* -------------- Traversal methods -------------- */
+
+    /**
+     * Returns the successor of p, or the head node if p.next has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node succ(Node p) {
+        Node next = p.next;
+        return (p == next) ? head : next;
+    }
+
+    /**
+     * Returns the first unmatched node of the given mode, or null if
+     * none.  Used by methods isEmpty, hasWaitingConsumer.
+     */
+    private Node firstOfMode(boolean isData) {
+        for (Node p = head; p != null; p = succ(p)) {
+            if (!p.isMatched())
+                return (p.isData == isData) ? p : null;
+        }
+        return null;
+    }
+
+    /**
+     * Returns the item in the first unmatched node with isData; or
+     * null if none.  Used by peek.
+     */
+    private E firstDataItem() {
+        for (Node p = head; p != null; p = succ(p)) {
+            Object item = p.item;
+            if (p.isData) {
+                if (item != null && item != p)
+                    return LinkedTransferQueue.<E>cast(item);
+            }
+            else if (item == null)
+                return null;
+        }
+        return null;
+    }
+
+    /**
+     * Traverses and counts unmatched nodes of the given mode.
+     * Used by methods size and getWaitingConsumerCount.
+     */
+    private int countOfMode(boolean data) {
+        int count = 0;
+        for (Node p = head; p != null; ) {
+            if (!p.isMatched()) {
+                if (p.isData != data)
+                    return 0;
+                if (++count == Integer.MAX_VALUE) // saturated
+                    break;
+            }
+            Node n = p.next;
+            if (n != p)
+                p = n;
+            else {
+                count = 0;
+                p = head;
+            }
+        }
+        return count;
+    }
+
+    final class Itr implements Iterator<E> {
+        private Node nextNode;   // next node to return item for
+        private E nextItem;      // the corresponding item
+        private Node lastRet;    // last returned node, to support remove
+        private Node lastPred;   // predecessor to unlink lastRet
+
+        /**
+         * Moves to next node after prev, or first node if prev null.
+         */
+        private void advance(Node prev) {
+            /*
+             * To track and avoid buildup of deleted nodes in the face
+             * of calls to both Queue.remove and Itr.remove, we must
+             * include variants of unsplice and sweep upon each
+             * advance: Upon Itr.remove, we may need to catch up links
+             * from lastPred, and upon other removes, we might need to
+             * skip ahead from stale nodes and unsplice deleted ones
+             * found while advancing.
+             */
+
+            Node r, b; // reset lastPred upon possible deletion of lastRet
+            if ((r = lastRet) != null && !r.isMatched())
+                lastPred = r;    // next lastPred is old lastRet
+            else if ((b = lastPred) == null || b.isMatched())
+                lastPred = null; // at start of list
+            else {
+                Node s, n;       // help with removal of lastPred.next
+                while ((s = b.next) != null &&
+                       s != b && s.isMatched() &&
+                       (n = s.next) != null && n != s)
+                    b.casNext(s, n);
+            }
+
+            this.lastRet = prev;
+
+            for (Node p = prev, s, n;;) {
+                s = (p == null) ? head : p.next;
+                if (s == null)
+                    break;
+                else if (s == p) {
+                    p = null;
+                    continue;
+                }
+                Object item = s.item;
+                if (s.isData) {
+                    if (item != null && item != s) {
+                        nextItem = LinkedTransferQueue.<E>cast(item);
+                        nextNode = s;
+                        return;
+                    }
+                }
+                else if (item == null)
+                    break;
+                // assert s.isMatched();
+                if (p == null)
+                    p = s;
+                else if ((n = s.next) == null)
+                    break;
+                else if (s == n)
+                    p = null;
+                else
+                    p.casNext(s, n);
+            }
+            nextNode = null;
+            nextItem = null;
+        }
+
+        Itr() {
+            advance(null);
+        }
+
+        public final boolean hasNext() {
+            return nextNode != null;
+        }
+
+        public final E next() {
+            Node p = nextNode;
+            if (p == null) throw new NoSuchElementException();
+            E e = nextItem;
+            advance(p);
+            return e;
+        }
+
+        public final void remove() {
+            final Node lastRet = this.lastRet;
+            if (lastRet == null)
+                throw new IllegalStateException();
+            this.lastRet = null;
+            if (lastRet.tryMatchData())
+                unsplice(lastPred, lastRet);
+        }
+    }
+
+    /* -------------- Removal methods -------------- */
+
+    /**
+     * Unsplices (now or later) the given deleted/cancelled node with
+     * the given predecessor.
+     *
+     * @param pred a node that was at one time known to be the
+     * predecessor of s, or null or s itself if s is/was at head
+     * @param s the node to be unspliced
+     */
+    final void unsplice(Node pred, Node s) {
+        s.forgetContents(); // forget unneeded fields
+        /*
+         * See above for rationale. Briefly: if pred still points to
+         * s, try to unlink s.  If s cannot be unlinked, because it is
+         * trailing node or pred might be unlinked, and neither pred
+         * nor s are head or offlist, add to sweepVotes, and if enough
+         * votes have accumulated, sweep.
+         */
+        if (pred != null && pred != s && pred.next == s) {
+            Node n = s.next;
+            if (n == null ||
+                (n != s && pred.casNext(s, n) && pred.isMatched())) {
+                for (;;) {               // check if at, or could be, head
+                    Node h = head;
+                    if (h == pred || h == s || h == null)
+                        return;          // at head or list empty
+                    if (!h.isMatched())
+                        break;
+                    Node hn = h.next;
+                    if (hn == null)
+                        return;          // now empty
+                    if (hn != h && casHead(h, hn))
+                        h.forgetNext();  // advance head
+                }
+                if (pred.next != pred && s.next != s) { // recheck if offlist
+                    for (;;) {           // sweep now if enough votes
+                        int v = sweepVotes;
+                        if (v < SWEEP_THRESHOLD) {
+                            if (casSweepVotes(v, v + 1))
+                                break;
+                        }
+                        else if (casSweepVotes(v, 0)) {
+                            sweep();
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Unlinks matched (typically cancelled) nodes encountered in a
+     * traversal from head.
+     */
+    private void sweep() {
+        for (Node p = head, s, n; p != null && (s = p.next) != null; ) {
+            if (!s.isMatched())
+                // Unmatched nodes are never self-linked
+                p = s;
+            else if ((n = s.next) == null) // trailing node is pinned
+                break;
+            else if (s == n)    // stale
+                // No need to also check for p == s, since that implies s == n
+                p = head;
+            else
+                p.casNext(s, n);
+        }
+    }
+
+    /**
+     * Main implementation of remove(Object)
+     */
+    private boolean findAndRemove(Object e) {
+        if (e != null) {
+            for (Node pred = null, p = head; p != null; ) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p && e.equals(item) &&
+                        p.tryMatchData()) {
+                        unsplice(pred, p);
+                        return true;
+                    }
+                }
+                else if (item == null)
+                    break;
+                pred = p;
+                if ((p = p.next) == pred) { // stale
+                    pred = null;
+                    p = head;
+                }
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Creates an initially empty {@code LinkedTransferQueue}.
+     */
+    public LinkedTransferQueue() {
+    }
+
+    /**
+     * Creates a {@code LinkedTransferQueue}
+     * initially containing the elements of the given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public LinkedTransferQueue(Collection<? extends E> c) {
+        this();
+        addAll(c);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never block.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void put(E e) {
+        xfer(e, true, ASYNC, 0);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never block or
+     * return {@code false}.
+     *
+     * @return {@code true} (as specified by
+     *  {@link java.util.concurrent.BlockingQueue#offer(Object,long,TimeUnit)
+     *  BlockingQueue.offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit) {
+        xfer(e, true, ASYNC, 0);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        xfer(e, true, ASYNC, 0);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never throw
+     * {@link IllegalStateException} or return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        xfer(e, true, ASYNC, 0);
+        return true;
+    }
+
+    /**
+     * Transfers the element to a waiting consumer immediately, if possible.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * otherwise returning {@code false} without enqueuing the element.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean tryTransfer(E e) {
+        return xfer(e, true, NOW, 0) == null;
+    }
+
+    /**
+     * Transfers the element to a consumer, waiting if necessary to do so.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else inserts the specified element at the tail of this queue
+     * and waits until the element is received by a consumer.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void transfer(E e) throws InterruptedException {
+        if (xfer(e, true, SYNC, 0) != null) {
+            Thread.interrupted(); // failure possible only due to interrupt
+            throw new InterruptedException();
+        }
+    }
+
+    /**
+     * Transfers the element to a consumer if it is possible to do so
+     * before the timeout elapses.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else inserts the specified element at the tail of this queue
+     * and waits until the element is received by a consumer,
+     * returning {@code false} if the specified wait time elapses
+     * before the element can be transferred.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean tryTransfer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null)
+            return true;
+        if (!Thread.interrupted())
+            return false;
+        throw new InterruptedException();
+    }
+
+    public E take() throws InterruptedException {
+        E e = xfer(null, false, SYNC, 0);
+        if (e != null)
+            return e;
+        Thread.interrupted();
+        throw new InterruptedException();
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E e = xfer(null, false, TIMED, unit.toNanos(timeout));
+        if (e != null || !Thread.interrupted())
+            return e;
+        throw new InterruptedException();
+    }
+
+    public E poll() {
+        return xfer(null, false, NOW, 0);
+    }
+
+    /**
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /**
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; n < maxElements && (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is a "weakly consistent" iterator that
+     * will never throw {@link java.util.ConcurrentModificationException
+     * ConcurrentModificationException}, and guarantees to traverse
+     * elements as they existed upon construction of the iterator, and
+     * may (but is not guaranteed to) reflect any modifications
+     * subsequent to construction.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    public E peek() {
+        return firstDataItem();
+    }
+
+    /**
+     * Returns {@code true} if this queue contains no elements.
+     *
+     * @return {@code true} if this queue contains no elements
+     */
+    public boolean isEmpty() {
+        for (Node p = head; p != null; p = succ(p)) {
+            if (!p.isMatched())
+                return !p.isData;
+        }
+        return true;
+    }
+
+    public boolean hasWaitingConsumer() {
+        return firstOfMode(false) != null;
+    }
+
+    /**
+     * Returns the number of elements in this queue.  If this queue
+     * contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these queues, determining the current
+     * number of elements requires an O(n) traversal.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        return countOfMode(true);
+    }
+
+    public int getWaitingConsumerCount() {
+        return countOfMode(false);
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        return findAndRemove(o);
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o == null) return false;
+        for (Node p = head; p != null; p = succ(p)) {
+            Object item = p.item;
+            if (p.isData) {
+                if (item != null && item != p && o.equals(item))
+                    return true;
+            }
+            else if (item == null)
+                break;
+        }
+        return false;
+    }
+
+    /**
+     * Always returns {@code Integer.MAX_VALUE} because a
+     * {@code LinkedTransferQueue} is not capacity constrained.
+     *
+     * @return {@code Integer.MAX_VALUE} (as specified by
+     *         {@link java.util.concurrent.BlockingQueue#remainingCapacity()
+     *         BlockingQueue.remainingCapacity})
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Saves the state to a stream (that is, serializes it).
+     *
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     * @param s the stream
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        s.defaultWriteObject();
+        for (E e : this)
+            s.writeObject(e);
+        // Use trailing null as sentinel
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes the Queue instance from a stream (that is,
+     * deserializes it).
+     *
+     * @param s the stream
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        for (;;) {
+            @SuppressWarnings("unchecked") E item = (E) s.readObject();
+            if (item == null)
+                break;
+            else
+                offer(item);
+        }
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long headOffset;
+    private static final long tailOffset;
+    private static final long sweepVotesOffset;
+    static {
+        try {
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = LinkedTransferQueue.class;
+            headOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("head"));
+            tailOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("tail"));
+            sweepVotesOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("sweepVotes"));
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/luni/src/main/java/java/util/concurrent/Phaser.java b/luni/src/main/java/java/util/concurrent/Phaser.java
new file mode 100644
index 0000000..25ff743
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/Phaser.java
@@ -0,0 +1,1135 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * A reusable synchronization barrier, similar in functionality to
+ * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and
+ * {@link java.util.concurrent.CountDownLatch CountDownLatch}
+ * but supporting more flexible usage.
+ *
+ * <p> <b>Registration.</b> Unlike the case for other barriers, the
+ * number of parties <em>registered</em> to synchronize on a phaser
+ * may vary over time.  Tasks may be registered at any time (using
+ * methods {@link #register}, {@link #bulkRegister}, or forms of
+ * constructors establishing initial numbers of parties), and
+ * optionally deregistered upon any arrival (using {@link
+ * #arriveAndDeregister}).  As is the case with most basic
+ * synchronization constructs, registration and deregistration affect
+ * only internal counts; they do not establish any further internal
+ * bookkeeping, so tasks cannot query whether they are registered.
+ * (However, you can introduce such bookkeeping by subclassing this
+ * class.)
+ *
+ * <p> <b>Synchronization.</b> Like a {@code CyclicBarrier}, a {@code
+ * Phaser} may be repeatedly awaited.  Method {@link
+ * #arriveAndAwaitAdvance} has effect analogous to {@link
+ * java.util.concurrent.CyclicBarrier#await CyclicBarrier.await}. Each
+ * generation of a phaser has an associated phase number. The phase
+ * number starts at zero, and advances when all parties arrive at the
+ * phaser, wrapping around to zero after reaching {@code
+ * Integer.MAX_VALUE}. The use of phase numbers enables independent
+ * control of actions upon arrival at a phaser and upon awaiting
+ * others, via two kinds of methods that may be invoked by any
+ * registered party:
+ *
+ * <ul>
+ *
+ *   <li> <b>Arrival.</b> Methods {@link #arrive} and
+ *       {@link #arriveAndDeregister} record arrival.  These methods
+ *       do not block, but return an associated <em>arrival phase
+ *       number</em>; that is, the phase number of the phaser to which
+ *       the arrival applied. When the final party for a given phase
+ *       arrives, an optional action is performed and the phase
+ *       advances.  These actions are performed by the party
+ *       triggering a phase advance, and are arranged by overriding
+ *       method {@link #onAdvance(int, int)}, which also controls
+ *       termination. Overriding this method is similar to, but more
+ *       flexible than, providing a barrier action to a {@code
+ *       CyclicBarrier}.
+ *
+ *   <li> <b>Waiting.</b> Method {@link #awaitAdvance} requires an
+ *       argument indicating an arrival phase number, and returns when
+ *       the phaser advances to (or is already at) a different phase.
+ *       Unlike similar constructions using {@code CyclicBarrier},
+ *       method {@code awaitAdvance} continues to wait even if the
+ *       waiting thread is interrupted. Interruptible and timeout
+ *       versions are also available, but exceptions encountered while
+ *       tasks wait interruptibly or with timeout do not change the
+ *       state of the phaser. If necessary, you can perform any
+ *       associated recovery within handlers of those exceptions,
+ *       often after invoking {@code forceTermination}.  Phasers may
+ *       also be used by tasks executing in a {@link ForkJoinPool},
+ *       which will ensure sufficient parallelism to execute tasks
+ *       when others are blocked waiting for a phase to advance.
+ *
+ * </ul>
+ *
+ * <p> <b>Termination.</b> A phaser may enter a <em>termination</em>
+ * state, that may be checked using method {@link #isTerminated}. Upon
+ * termination, all synchronization methods immediately return without
+ * waiting for advance, as indicated by a negative return value.
+ * Similarly, attempts to register upon termination have no effect.
+ * Termination is triggered when an invocation of {@code onAdvance}
+ * returns {@code true}. The default implementation returns {@code
+ * true} if a deregistration has caused the number of registered
+ * parties to become zero.  As illustrated below, when phasers control
+ * actions with a fixed number of iterations, it is often convenient
+ * to override this method to cause termination when the current phase
+ * number reaches a threshold. Method {@link #forceTermination} is
+ * also available to abruptly release waiting threads and allow them
+ * to terminate.
+ *
+ * <p> <b>Tiering.</b> Phasers may be <em>tiered</em> (i.e.,
+ * constructed in tree structures) to reduce contention. Phasers with
+ * large numbers of parties that would otherwise experience heavy
+ * synchronization contention costs may instead be set up so that
+ * groups of sub-phasers share a common parent.  This may greatly
+ * increase throughput even though it incurs greater per-operation
+ * overhead.
+ *
+ * <p>In a tree of tiered phasers, registration and deregistration of
+ * child phasers with their parent are managed automatically.
+ * Whenever the number of registered parties of a child phaser becomes
+ * non-zero (as established in the {@link #Phaser(Phaser,int)}
+ * constructor, {@link #register}, or {@link #bulkRegister}), the
+ * child phaser is registered with its parent.  Whenever the number of
+ * registered parties becomes zero as the result of an invocation of
+ * {@link #arriveAndDeregister}, the child phaser is deregistered
+ * from its parent.
+ *
+ * <p><b>Monitoring.</b> While synchronization methods may be invoked
+ * only by registered parties, the current state of a phaser may be
+ * monitored by any caller.  At any given moment there are {@link
+ * #getRegisteredParties} parties in total, of which {@link
+ * #getArrivedParties} have arrived at the current phase ({@link
+ * #getPhase}).  When the remaining ({@link #getUnarrivedParties})
+ * parties arrive, the phase advances.  The values returned by these
+ * methods may reflect transient states and so are not in general
+ * useful for synchronization control.  Method {@link #toString}
+ * returns snapshots of these state queries in a form convenient for
+ * informal monitoring.
+ *
+ * <p><b>Sample usages:</b>
+ *
+ * <p>A {@code Phaser} may be used instead of a {@code CountDownLatch}
+ * to control a one-shot action serving a variable number of parties.
+ * The typical idiom is for the method setting this up to first
+ * register, then start the actions, then deregister, as in:
+ *
+ *  <pre> {@code
+ * void runTasks(List<Runnable> tasks) {
+ *   final Phaser phaser = new Phaser(1); // "1" to register self
+ *   // create and start threads
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         phaser.arriveAndAwaitAdvance(); // await all creation
+ *         task.run();
+ *       }
+ *     }.start();
+ *   }
+ *
+ *   // allow threads to start and deregister self
+ *   phaser.arriveAndDeregister();
+ * }}</pre>
+ *
+ * <p>One way to cause a set of threads to repeatedly perform actions
+ * for a given number of iterations is to override {@code onAdvance}:
+ *
+ *  <pre> {@code
+ * void startTasks(List<Runnable> tasks, final int iterations) {
+ *   final Phaser phaser = new Phaser() {
+ *     protected boolean onAdvance(int phase, int registeredParties) {
+ *       return phase >= iterations || registeredParties == 0;
+ *     }
+ *   };
+ *   phaser.register();
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         do {
+ *           task.run();
+ *           phaser.arriveAndAwaitAdvance();
+ *         } while (!phaser.isTerminated());
+ *       }
+ *     }.start();
+ *   }
+ *   phaser.arriveAndDeregister(); // deregister self, don't wait
+ * }}</pre>
+ *
+ * If the main task must later await termination, it
+ * may re-register and then execute a similar loop:
+ *  <pre> {@code
+ *   // ...
+ *   phaser.register();
+ *   while (!phaser.isTerminated())
+ *     phaser.arriveAndAwaitAdvance();}</pre>
+ *
+ * <p>Related constructions may be used to await particular phase numbers
+ * in contexts where you are sure that the phase will never wrap around
+ * {@code Integer.MAX_VALUE}. For example:
+ *
+ *  <pre> {@code
+ * void awaitPhase(Phaser phaser, int phase) {
+ *   int p = phaser.register(); // assumes caller not already registered
+ *   while (p < phase) {
+ *     if (phaser.isTerminated())
+ *       // ... deal with unexpected termination
+ *     else
+ *       p = phaser.arriveAndAwaitAdvance();
+ *   }
+ *   phaser.arriveAndDeregister();
+ * }}</pre>
+ *
+ *
+ * <p>To create a set of {@code n} tasks using a tree of phasers, you
+ * could use code of the following form, assuming a Task class with a
+ * constructor accepting a {@code Phaser} that it registers with upon
+ * construction. After invocation of {@code build(new Task[n], 0, n,
+ * new Phaser())}, these tasks could then be started, for example by
+ * submitting to a pool:
+ *
+ *  <pre> {@code
+ * void build(Task[] tasks, int lo, int hi, Phaser ph) {
+ *   if (hi - lo > TASKS_PER_PHASER) {
+ *     for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
+ *       int j = Math.min(i + TASKS_PER_PHASER, hi);
+ *       build(tasks, i, j, new Phaser(ph));
+ *     }
+ *   } else {
+ *     for (int i = lo; i < hi; ++i)
+ *       tasks[i] = new Task(ph);
+ *       // assumes new Task(ph) performs ph.register()
+ *   }
+ * }}</pre>
+ *
+ * The best value of {@code TASKS_PER_PHASER} depends mainly on
+ * expected synchronization rates. A value as low as four may
+ * be appropriate for extremely small per-phase task bodies (thus
+ * high rates), or up to hundreds for extremely large ones.
+ *
+ * <p><b>Implementation notes</b>: This implementation restricts the
+ * maximum number of parties to 65535. Attempts to register additional
+ * parties result in {@code IllegalStateException}. However, you can and
+ * should create tiered phasers to accommodate arbitrarily large sets
+ * of participants.
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ */
+public class Phaser {
+    /*
+     * This class implements an extension of X10 "clocks".  Thanks to
+     * Vijay Saraswat for the idea, and to Vivek Sarkar for
+     * enhancements to extend functionality.
+     */
+
+    /**
+     * Primary state representation, holding four bit-fields:
+     *
+     * unarrived  -- the number of parties yet to hit barrier (bits  0-15)
+     * parties    -- the number of parties to wait            (bits 16-31)
+     * phase      -- the generation of the barrier            (bits 32-62)
+     * terminated -- set if barrier is terminated             (bit  63 / sign)
+     *
+     * Except that a phaser with no registered parties is
+     * distinguished by the otherwise illegal state of having zero
+     * parties and one unarrived parties (encoded as EMPTY below).
+     *
+     * To efficiently maintain atomicity, these values are packed into
+     * a single (atomic) long. Good performance relies on keeping
+     * state decoding and encoding simple, and keeping race windows
+     * short.
+     *
+     * All state updates are performed via CAS except initial
+     * registration of a sub-phaser (i.e., one with a non-null
+     * parent).  In this (relatively rare) case, we use built-in
+     * synchronization to lock while first registering with its
+     * parent.
+     *
+     * The phase of a subphaser is allowed to lag that of its
+     * ancestors until it is actually accessed -- see method
+     * reconcileState.
+     */
+    private volatile long state;
+
+    private static final int  MAX_PARTIES     = 0xffff;
+    private static final int  MAX_PHASE       = Integer.MAX_VALUE;
+    private static final int  PARTIES_SHIFT   = 16;
+    private static final int  PHASE_SHIFT     = 32;
+    private static final int  UNARRIVED_MASK  = 0xffff;      // to mask ints
+    private static final long PARTIES_MASK    = 0xffff0000L; // to mask longs
+    private static final long COUNTS_MASK     = 0xffffffffL;
+    private static final long TERMINATION_BIT = 1L << 63;
+
+    // some special values
+    private static final int  ONE_ARRIVAL     = 1;
+    private static final int  ONE_PARTY       = 1 << PARTIES_SHIFT;
+    private static final int  ONE_DEREGISTER  = ONE_ARRIVAL|ONE_PARTY;
+    private static final int  EMPTY           = 1;
+
+    // The following unpacking methods are usually manually inlined
+
+    private static int unarrivedOf(long s) {
+        int counts = (int)s;
+        return (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
+    }
+
+    private static int partiesOf(long s) {
+        return (int)s >>> PARTIES_SHIFT;
+    }
+
+    private static int phaseOf(long s) {
+        return (int)(s >>> PHASE_SHIFT);
+    }
+
+    private static int arrivedOf(long s) {
+        int counts = (int)s;
+        return (counts == EMPTY) ? 0 :
+            (counts >>> PARTIES_SHIFT) - (counts & UNARRIVED_MASK);
+    }
+
+    /**
+     * The parent of this phaser, or null if none
+     */
+    private final Phaser parent;
+
+    /**
+     * The root of phaser tree. Equals this if not in a tree.
+     */
+    private final Phaser root;
+
+    /**
+     * Heads of Treiber stacks for waiting threads. To eliminate
+     * contention when releasing some threads while adding others, we
+     * use two of them, alternating across even and odd phases.
+     * Subphasers share queues with root to speed up releases.
+     */
+    private final AtomicReference<QNode> evenQ;
+    private final AtomicReference<QNode> oddQ;
+
+    private AtomicReference<QNode> queueFor(int phase) {
+        return ((phase & 1) == 0) ? evenQ : oddQ;
+    }
+
+    /**
+     * Returns message string for bounds exceptions on arrival.
+     */
+    private String badArrive(long s) {
+        return "Attempted arrival of unregistered party for " +
+            stateToString(s);
+    }
+
+    /**
+     * Returns message string for bounds exceptions on registration.
+     */
+    private String badRegister(long s) {
+        return "Attempt to register more than " +
+            MAX_PARTIES + " parties for " + stateToString(s);
+    }
+
+    /**
+     * Main implementation for methods arrive and arriveAndDeregister.
+     * Manually tuned to speed up and minimize race windows for the
+     * common case of just decrementing unarrived field.
+     *
+     * @param adjust value to subtract from state;
+     *               ONE_ARRIVAL for arrive,
+     *               ONE_DEREGISTER for arriveAndDeregister
+     */
+    private int doArrive(int adjust) {
+        final Phaser root = this.root;
+        for (;;) {
+            long s = (root == this) ? state : reconcileState();
+            int phase = (int)(s >>> PHASE_SHIFT);
+            if (phase < 0)
+                return phase;
+            int counts = (int)s;
+            int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
+            if (unarrived <= 0)
+                throw new IllegalStateException(badArrive(s));
+            if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adjust)) {
+                if (unarrived == 1) {
+                    long n = s & PARTIES_MASK;  // base of next state
+                    int nextUnarrived = (int)n >>> PARTIES_SHIFT;
+                    if (root == this) {
+                        if (onAdvance(phase, nextUnarrived))
+                            n |= TERMINATION_BIT;
+                        else if (nextUnarrived == 0)
+                            n |= EMPTY;
+                        else
+                            n |= nextUnarrived;
+                        int nextPhase = (phase + 1) & MAX_PHASE;
+                        n |= (long)nextPhase << PHASE_SHIFT;
+                        UNSAFE.compareAndSwapLong(this, stateOffset, s, n);
+                        releaseWaiters(phase);
+                    }
+                    else if (nextUnarrived == 0) { // propagate deregistration
+                        phase = parent.doArrive(ONE_DEREGISTER);
+                        UNSAFE.compareAndSwapLong(this, stateOffset,
+                                                  s, s | EMPTY);
+                    }
+                    else
+                        phase = parent.doArrive(ONE_ARRIVAL);
+                }
+                return phase;
+            }
+        }
+    }
+
+    /**
+     * Implementation of register, bulkRegister
+     *
+     * @param registrations number to add to both parties and
+     * unarrived fields. Must be greater than zero.
+     */
+    private int doRegister(int registrations) {
+        // adjustment to state
+        long adjust = ((long)registrations << PARTIES_SHIFT) | registrations;
+        final Phaser parent = this.parent;
+        int phase;
+        for (;;) {
+            long s = (parent == null) ? state : reconcileState();
+            int counts = (int)s;
+            int parties = counts >>> PARTIES_SHIFT;
+            int unarrived = counts & UNARRIVED_MASK;
+            if (registrations > MAX_PARTIES - parties)
+                throw new IllegalStateException(badRegister(s));
+            phase = (int)(s >>> PHASE_SHIFT);
+            if (phase < 0)
+                break;
+            if (counts != EMPTY) {                  // not 1st registration
+                if (parent == null || reconcileState() == s) {
+                    if (unarrived == 0)             // wait out advance
+                        root.internalAwaitAdvance(phase, null);
+                    else if (UNSAFE.compareAndSwapLong(this, stateOffset,
+                                                       s, s + adjust))
+                        break;
+                }
+            }
+            else if (parent == null) {              // 1st root registration
+                long next = ((long)phase << PHASE_SHIFT) | adjust;
+                if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))
+                    break;
+            }
+            else {
+                synchronized (this) {               // 1st sub registration
+                    if (state == s) {               // recheck under lock
+                        phase = parent.doRegister(1);
+                        if (phase < 0)
+                            break;
+                        // finish registration whenever parent registration
+                        // succeeded, even when racing with termination,
+                        // since these are part of the same "transaction".
+                        while (!UNSAFE.compareAndSwapLong
+                               (this, stateOffset, s,
+                                ((long)phase << PHASE_SHIFT) | adjust)) {
+                            s = state;
+                            phase = (int)(root.state >>> PHASE_SHIFT);
+                            // assert (int)s == EMPTY;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        return phase;
+    }
+
+    /**
+     * Resolves lagged phase propagation from root if necessary.
+     * Reconciliation normally occurs when root has advanced but
+     * subphasers have not yet done so, in which case they must finish
+     * their own advance by setting unarrived to parties (or if
+     * parties is zero, resetting to unregistered EMPTY state).
+     *
+     * @return reconciled state
+     */
+    private long reconcileState() {
+        final Phaser root = this.root;
+        long s = state;
+        if (root != this) {
+            int phase, p;
+            // CAS to root phase with current parties, tripping unarrived
+            while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
+                   (int)(s >>> PHASE_SHIFT) &&
+                   !UNSAFE.compareAndSwapLong
+                   (this, stateOffset, s,
+                    s = (((long)phase << PHASE_SHIFT) |
+                         ((phase < 0) ? (s & COUNTS_MASK) :
+                          (((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
+                           ((s & PARTIES_MASK) | p))))))
+                s = state;
+        }
+        return s;
+    }
+
+    /**
+     * Creates a new phaser with no initially registered parties, no
+     * parent, and initial phase number 0. Any thread using this
+     * phaser will need to first register for it.
+     */
+    public Phaser() {
+        this(null, 0);
+    }
+
+    /**
+     * Creates a new phaser with the given number of registered
+     * unarrived parties, no parent, and initial phase number 0.
+     *
+     * @param parties the number of parties required to advance to the
+     * next phase
+     * @throws IllegalArgumentException if parties less than zero
+     * or greater than the maximum number of parties supported
+     */
+    public Phaser(int parties) {
+        this(null, parties);
+    }
+
+    /**
+     * Equivalent to {@link #Phaser(Phaser, int) Phaser(parent, 0)}.
+     *
+     * @param parent the parent phaser
+     */
+    public Phaser(Phaser parent) {
+        this(parent, 0);
+    }
+
+    /**
+     * Creates a new phaser with the given parent and number of
+     * registered unarrived parties.  When the given parent is non-null
+     * and the given number of parties is greater than zero, this
+     * child phaser is registered with its parent.
+     *
+     * @param parent the parent phaser
+     * @param parties the number of parties required to advance to the
+     * next phase
+     * @throws IllegalArgumentException if parties less than zero
+     * or greater than the maximum number of parties supported
+     */
+    public Phaser(Phaser parent, int parties) {
+        if (parties >>> PARTIES_SHIFT != 0)
+            throw new IllegalArgumentException("Illegal number of parties");
+        int phase = 0;
+        this.parent = parent;
+        if (parent != null) {
+            final Phaser root = parent.root;
+            this.root = root;
+            this.evenQ = root.evenQ;
+            this.oddQ = root.oddQ;
+            if (parties != 0)
+                phase = parent.doRegister(1);
+        }
+        else {
+            this.root = this;
+            this.evenQ = new AtomicReference<QNode>();
+            this.oddQ = new AtomicReference<QNode>();
+        }
+        this.state = (parties == 0) ? (long)EMPTY :
+            ((long)phase << PHASE_SHIFT) |
+            ((long)parties << PARTIES_SHIFT) |
+            ((long)parties);
+    }
+
+    /**
+     * Adds a new unarrived party to this phaser.  If an ongoing
+     * invocation of {@link #onAdvance} is in progress, this method
+     * may await its completion before returning.  If this phaser has
+     * a parent, and this phaser previously had no registered parties,
+     * this child phaser is also registered with its parent. If
+     * this phaser is terminated, the attempt to register has
+     * no effect, and a negative value is returned.
+     *
+     * @return the arrival phase number to which this registration
+     * applied.  If this value is negative, then this phaser has
+     * terminated, in which case registration has no effect.
+     * @throws IllegalStateException if attempting to register more
+     * than the maximum supported number of parties
+     */
+    public int register() {
+        return doRegister(1);
+    }
+
+    /**
+     * Adds the given number of new unarrived parties to this phaser.
+     * If an ongoing invocation of {@link #onAdvance} is in progress,
+     * this method may await its completion before returning.  If this
+     * phaser has a parent, and the given number of parties is greater
+     * than zero, and this phaser previously had no registered
+     * parties, this child phaser is also registered with its parent.
+     * If this phaser is terminated, the attempt to register has no
+     * effect, and a negative value is returned.
+     *
+     * @param parties the number of additional parties required to
+     * advance to the next phase
+     * @return the arrival phase number to which this registration
+     * applied.  If this value is negative, then this phaser has
+     * terminated, in which case registration has no effect.
+     * @throws IllegalStateException if attempting to register more
+     * than the maximum supported number of parties
+     * @throws IllegalArgumentException if {@code parties < 0}
+     */
+    public int bulkRegister(int parties) {
+        if (parties < 0)
+            throw new IllegalArgumentException();
+        if (parties == 0)
+            return getPhase();
+        return doRegister(parties);
+    }
+
+    /**
+     * Arrives at this phaser, without waiting for others to arrive.
+     *
+     * <p>It is a usage error for an unregistered party to invoke this
+     * method.  However, this error may result in an {@code
+     * IllegalStateException} only upon some subsequent operation on
+     * this phaser, if ever.
+     *
+     * @return the arrival phase number, or a negative value if terminated
+     * @throws IllegalStateException if not terminated and the number
+     * of unarrived parties would become negative
+     */
+    public int arrive() {
+        return doArrive(ONE_ARRIVAL);
+    }
+
+    /**
+     * Arrives at this phaser and deregisters from it without waiting
+     * for others to arrive. Deregistration reduces the number of
+     * parties required to advance in future phases.  If this phaser
+     * has a parent, and deregistration causes this phaser to have
+     * zero parties, this phaser is also deregistered from its parent.
+     *
+     * <p>It is a usage error for an unregistered party to invoke this
+     * method.  However, this error may result in an {@code
+     * IllegalStateException} only upon some subsequent operation on
+     * this phaser, if ever.
+     *
+     * @return the arrival phase number, or a negative value if terminated
+     * @throws IllegalStateException if not terminated and the number
+     * of registered or unarrived parties would become negative
+     */
+    public int arriveAndDeregister() {
+        return doArrive(ONE_DEREGISTER);
+    }
+
+    /**
+     * Arrives at this phaser and awaits others. Equivalent in effect
+     * to {@code awaitAdvance(arrive())}.  If you need to await with
+     * interruption or timeout, you can arrange this with an analogous
+     * construction using one of the other forms of the {@code
+     * awaitAdvance} method.  If instead you need to deregister upon
+     * arrival, use {@code awaitAdvance(arriveAndDeregister())}.
+     *
+     * <p>It is a usage error for an unregistered party to invoke this
+     * method.  However, this error may result in an {@code
+     * IllegalStateException} only upon some subsequent operation on
+     * this phaser, if ever.
+     *
+     * @return the arrival phase number, or the (negative)
+     * {@linkplain #getPhase() current phase} if terminated
+     * @throws IllegalStateException if not terminated and the number
+     * of unarrived parties would become negative
+     */
+    public int arriveAndAwaitAdvance() {
+        // Specialization of doArrive+awaitAdvance eliminating some reads/paths
+        final Phaser root = this.root;
+        for (;;) {
+            long s = (root == this) ? state : reconcileState();
+            int phase = (int)(s >>> PHASE_SHIFT);
+            if (phase < 0)
+                return phase;
+            int counts = (int)s;
+            int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
+            if (unarrived <= 0)
+                throw new IllegalStateException(badArrive(s));
+            if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
+                                          s -= ONE_ARRIVAL)) {
+                if (unarrived > 1)
+                    return root.internalAwaitAdvance(phase, null);
+                if (root != this)
+                    return parent.arriveAndAwaitAdvance();
+                long n = s & PARTIES_MASK;  // base of next state
+                int nextUnarrived = (int)n >>> PARTIES_SHIFT;
+                if (onAdvance(phase, nextUnarrived))
+                    n |= TERMINATION_BIT;
+                else if (nextUnarrived == 0)
+                    n |= EMPTY;
+                else
+                    n |= nextUnarrived;
+                int nextPhase = (phase + 1) & MAX_PHASE;
+                n |= (long)nextPhase << PHASE_SHIFT;
+                if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))
+                    return (int)(state >>> PHASE_SHIFT); // terminated
+                releaseWaiters(phase);
+                return nextPhase;
+            }
+        }
+    }
+
+    /**
+     * Awaits the phase of this phaser to advance from the given phase
+     * value, returning immediately if the current phase is not equal
+     * to the given phase value or this phaser is terminated.
+     *
+     * @param phase an arrival phase number, or negative value if
+     * terminated; this argument is normally the value returned by a
+     * previous call to {@code arrive} or {@code arriveAndDeregister}.
+     * @return the next arrival phase number, or the argument if it is
+     * negative, or the (negative) {@linkplain #getPhase() current phase}
+     * if terminated
+     */
+    public int awaitAdvance(int phase) {
+        final Phaser root = this.root;
+        long s = (root == this) ? state : reconcileState();
+        int p = (int)(s >>> PHASE_SHIFT);
+        if (phase < 0)
+            return phase;
+        if (p == phase)
+            return root.internalAwaitAdvance(phase, null);
+        return p;
+    }
+
+    /**
+     * Awaits the phase of this phaser to advance from the given phase
+     * value, throwing {@code InterruptedException} if interrupted
+     * while waiting, or returning immediately if the current phase is
+     * not equal to the given phase value or this phaser is
+     * terminated.
+     *
+     * @param phase an arrival phase number, or negative value if
+     * terminated; this argument is normally the value returned by a
+     * previous call to {@code arrive} or {@code arriveAndDeregister}.
+     * @return the next arrival phase number, or the argument if it is
+     * negative, or the (negative) {@linkplain #getPhase() current phase}
+     * if terminated
+     * @throws InterruptedException if thread interrupted while waiting
+     */
+    public int awaitAdvanceInterruptibly(int phase)
+        throws InterruptedException {
+        final Phaser root = this.root;
+        long s = (root == this) ? state : reconcileState();
+        int p = (int)(s >>> PHASE_SHIFT);
+        if (phase < 0)
+            return phase;
+        if (p == phase) {
+            QNode node = new QNode(this, phase, true, false, 0L);
+            p = root.internalAwaitAdvance(phase, node);
+            if (node.wasInterrupted)
+                throw new InterruptedException();
+        }
+        return p;
+    }
+
+    /**
+     * Awaits the phase of this phaser to advance from the given phase
+     * value or the given timeout to elapse, throwing {@code
+     * InterruptedException} if interrupted while waiting, or
+     * returning immediately if the current phase is not equal to the
+     * given phase value or this phaser is terminated.
+     *
+     * @param phase an arrival phase number, or negative value if
+     * terminated; this argument is normally the value returned by a
+     * previous call to {@code arrive} or {@code arriveAndDeregister}.
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the next arrival phase number, or the argument if it is
+     * negative, or the (negative) {@linkplain #getPhase() current phase}
+     * if terminated
+     * @throws InterruptedException if thread interrupted while waiting
+     * @throws TimeoutException if timed out while waiting
+     */
+    public int awaitAdvanceInterruptibly(int phase,
+                                         long timeout, TimeUnit unit)
+        throws InterruptedException, TimeoutException {
+        long nanos = unit.toNanos(timeout);
+        final Phaser root = this.root;
+        long s = (root == this) ? state : reconcileState();
+        int p = (int)(s >>> PHASE_SHIFT);
+        if (phase < 0)
+            return phase;
+        if (p == phase) {
+            QNode node = new QNode(this, phase, true, true, nanos);
+            p = root.internalAwaitAdvance(phase, node);
+            if (node.wasInterrupted)
+                throw new InterruptedException();
+            else if (p == phase)
+                throw new TimeoutException();
+        }
+        return p;
+    }
+
+    /**
+     * Forces this phaser to enter termination state.  Counts of
+     * registered parties are unaffected.  If this phaser is a member
+     * of a tiered set of phasers, then all of the phasers in the set
+     * are terminated.  If this phaser is already terminated, this
+     * method has no effect.  This method may be useful for
+     * coordinating recovery after one or more tasks encounter
+     * unexpected exceptions.
+     */
+    public void forceTermination() {
+        // Only need to change root state
+        final Phaser root = this.root;
+        long s;
+        while ((s = root.state) >= 0) {
+            if (UNSAFE.compareAndSwapLong(root, stateOffset,
+                                          s, s | TERMINATION_BIT)) {
+                // signal all threads
+                releaseWaiters(0); // Waiters on evenQ
+                releaseWaiters(1); // Waiters on oddQ
+                return;
+            }
+        }
+    }
+
+    /**
+     * Returns the current phase number. The maximum phase number is
+     * {@code Integer.MAX_VALUE}, after which it restarts at
+     * zero. Upon termination, the phase number is negative,
+     * in which case the prevailing phase prior to termination
+     * may be obtained via {@code getPhase() + Integer.MIN_VALUE}.
+     *
+     * @return the phase number, or a negative value if terminated
+     */
+    public final int getPhase() {
+        return (int)(root.state >>> PHASE_SHIFT);
+    }
+
+    /**
+     * Returns the number of parties registered at this phaser.
+     *
+     * @return the number of parties
+     */
+    public int getRegisteredParties() {
+        return partiesOf(state);
+    }
+
+    /**
+     * Returns the number of registered parties that have arrived at
+     * the current phase of this phaser. If this phaser has terminated,
+     * the returned value is meaningless and arbitrary.
+     *
+     * @return the number of arrived parties
+     */
+    public int getArrivedParties() {
+        return arrivedOf(reconcileState());
+    }
+
+    /**
+     * Returns the number of registered parties that have not yet
+     * arrived at the current phase of this phaser. If this phaser has
+     * terminated, the returned value is meaningless and arbitrary.
+     *
+     * @return the number of unarrived parties
+     */
+    public int getUnarrivedParties() {
+        return unarrivedOf(reconcileState());
+    }
+
+    /**
+     * Returns the parent of this phaser, or {@code null} if none.
+     *
+     * @return the parent of this phaser, or {@code null} if none
+     */
+    public Phaser getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns the root ancestor of this phaser, which is the same as
+     * this phaser if it has no parent.
+     *
+     * @return the root ancestor of this phaser
+     */
+    public Phaser getRoot() {
+        return root;
+    }
+
+    /**
+     * Returns {@code true} if this phaser has been terminated.
+     *
+     * @return {@code true} if this phaser has been terminated
+     */
+    public boolean isTerminated() {
+        return root.state < 0L;
+    }
+
+    /**
+     * Overridable method to perform an action upon impending phase
+     * advance, and to control termination. This method is invoked
+     * upon arrival of the party advancing this phaser (when all other
+     * waiting parties are dormant).  If this method returns {@code
+     * true}, this phaser will be set to a final termination state
+     * upon advance, and subsequent calls to {@link #isTerminated}
+     * will return true. Any (unchecked) Exception or Error thrown by
+     * an invocation of this method is propagated to the party
+     * attempting to advance this phaser, in which case no advance
+     * occurs.
+     *
+     * <p>The arguments to this method provide the state of the phaser
+     * prevailing for the current transition.  The effects of invoking
+     * arrival, registration, and waiting methods on this phaser from
+     * within {@code onAdvance} are unspecified and should not be
+     * relied on.
+     *
+     * <p>If this phaser is a member of a tiered set of phasers, then
+     * {@code onAdvance} is invoked only for its root phaser on each
+     * advance.
+     *
+     * <p>To support the most common use cases, the default
+     * implementation of this method returns {@code true} when the
+     * number of registered parties has become zero as the result of a
+     * party invoking {@code arriveAndDeregister}.  You can disable
+     * this behavior, thus enabling continuation upon future
+     * registrations, by overriding this method to always return
+     * {@code false}:
+     *
+     * <pre> {@code
+     * Phaser phaser = new Phaser() {
+     *   protected boolean onAdvance(int phase, int parties) { return false; }
+     * }}</pre>
+     *
+     * @param phase the current phase number on entry to this method,
+     * before this phaser is advanced
+     * @param registeredParties the current number of registered parties
+     * @return {@code true} if this phaser should terminate
+     */
+    protected boolean onAdvance(int phase, int registeredParties) {
+        return registeredParties == 0;
+    }
+
+    /**
+     * Returns a string identifying this phaser, as well as its
+     * state.  The state, in brackets, includes the String {@code
+     * "phase = "} followed by the phase number, {@code "parties = "}
+     * followed by the number of registered parties, and {@code
+     * "arrived = "} followed by the number of arrived parties.
+     *
+     * @return a string identifying this phaser, as well as its state
+     */
+    public String toString() {
+        return stateToString(reconcileState());
+    }
+
+    /**
+     * Implementation of toString and string-based error messages
+     */
+    private String stateToString(long s) {
+        return super.toString() +
+            "[phase = " + phaseOf(s) +
+            " parties = " + partiesOf(s) +
+            " arrived = " + arrivedOf(s) + "]";
+    }
+
+    // Waiting mechanics
+
+    /**
+     * Removes and signals threads from queue for phase.
+     */
+    private void releaseWaiters(int phase) {
+        QNode q;   // first element of queue
+        Thread t;  // its thread
+        AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
+        while ((q = head.get()) != null &&
+               q.phase != (int)(root.state >>> PHASE_SHIFT)) {
+            if (head.compareAndSet(q, q.next) &&
+                (t = q.thread) != null) {
+                q.thread = null;
+                LockSupport.unpark(t);
+            }
+        }
+    }
+
+    /**
+     * Variant of releaseWaiters that additionally tries to remove any
+     * nodes no longer waiting for advance due to timeout or
+     * interrupt. Currently, nodes are removed only if they are at
+     * head of queue, which suffices to reduce memory footprint in
+     * most usages.
+     *
+     * @return current phase on exit
+     */
+    private int abortWait(int phase) {
+        AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
+        for (;;) {
+            Thread t;
+            QNode q = head.get();
+            int p = (int)(root.state >>> PHASE_SHIFT);
+            if (q == null || ((t = q.thread) != null && q.phase == p))
+                return p;
+            if (head.compareAndSet(q, q.next) && t != null) {
+                q.thread = null;
+                LockSupport.unpark(t);
+            }
+        }
+    }
+
+    /** The number of CPUs, for spin control */
+    private static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * The number of times to spin before blocking while waiting for
+     * advance, per arrival while waiting. On multiprocessors, fully
+     * blocking and waking up a large number of threads all at once is
+     * usually a very slow process, so we use rechargeable spins to
+     * avoid it when threads regularly arrive: When a thread in
+     * internalAwaitAdvance notices another arrival before blocking,
+     * and there appear to be enough CPUs available, it spins
+     * SPINS_PER_ARRIVAL more times before blocking. The value trades
+     * off good-citizenship vs big unnecessary slowdowns.
+     */
+    static final int SPINS_PER_ARRIVAL = (NCPU < 2) ? 1 : 1 << 8;
+
+    /**
+     * Possibly blocks and waits for phase to advance unless aborted.
+     * Call only on root phaser.
+     *
+     * @param phase current phase
+     * @param node if non-null, the wait node to track interrupt and timeout;
+     * if null, denotes noninterruptible wait
+     * @return current phase
+     */
+    private int internalAwaitAdvance(int phase, QNode node) {
+        // assert root == this;
+        releaseWaiters(phase-1);          // ensure old queue clean
+        boolean queued = false;           // true when node is enqueued
+        int lastUnarrived = 0;            // to increase spins upon change
+        int spins = SPINS_PER_ARRIVAL;
+        long s;
+        int p;
+        while ((p = (int)((s = state) >>> PHASE_SHIFT)) == phase) {
+            if (node == null) {           // spinning in noninterruptible mode
+                int unarrived = (int)s & UNARRIVED_MASK;
+                if (unarrived != lastUnarrived &&
+                    (lastUnarrived = unarrived) < NCPU)
+                    spins += SPINS_PER_ARRIVAL;
+                boolean interrupted = Thread.interrupted();
+                if (interrupted || --spins < 0) { // need node to record intr
+                    node = new QNode(this, phase, false, false, 0L);
+                    node.wasInterrupted = interrupted;
+                }
+            }
+            else if (node.isReleasable()) // done or aborted
+                break;
+            else if (!queued) {           // push onto queue
+                AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
+                QNode q = node.next = head.get();
+                if ((q == null || q.phase == phase) &&
+                    (int)(state >>> PHASE_SHIFT) == phase) // avoid stale enq
+                    queued = head.compareAndSet(q, node);
+            }
+            else {
+                try {
+                    ForkJoinPool.managedBlock(node);
+                } catch (InterruptedException ie) {
+                    node.wasInterrupted = true;
+                }
+            }
+        }
+
+        if (node != null) {
+            if (node.thread != null)
+                node.thread = null;       // avoid need for unpark()
+            if (node.wasInterrupted && !node.interruptible)
+                Thread.currentThread().interrupt();
+            if (p == phase && (p = (int)(state >>> PHASE_SHIFT)) == phase)
+                return abortWait(phase); // possibly clean up on abort
+        }
+        releaseWaiters(phase);
+        return p;
+    }
+
+    /**
+     * Wait nodes for Treiber stack representing wait queue
+     */
+    static final class QNode implements ForkJoinPool.ManagedBlocker {
+        final Phaser phaser;
+        final int phase;
+        final boolean interruptible;
+        final boolean timed;
+        boolean wasInterrupted;
+        long nanos;
+        long lastTime;
+        volatile Thread thread; // nulled to cancel wait
+        QNode next;
+
+        QNode(Phaser phaser, int phase, boolean interruptible,
+              boolean timed, long nanos) {
+            this.phaser = phaser;
+            this.phase = phase;
+            this.interruptible = interruptible;
+            this.nanos = nanos;
+            this.timed = timed;
+            this.lastTime = timed ? System.nanoTime() : 0L;
+            thread = Thread.currentThread();
+        }
+
+        public boolean isReleasable() {
+            if (thread == null)
+                return true;
+            if (phaser.getPhase() != phase) {
+                thread = null;
+                return true;
+            }
+            if (Thread.interrupted())
+                wasInterrupted = true;
+            if (wasInterrupted && interruptible) {
+                thread = null;
+                return true;
+            }
+            if (timed) {
+                if (nanos > 0L) {
+                    long now = System.nanoTime();
+                    nanos -= now - lastTime;
+                    lastTime = now;
+                }
+                if (nanos <= 0L) {
+                    thread = null;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean block() {
+            if (isReleasable())
+                return true;
+            else if (!timed)
+                LockSupport.park(this);
+            else if (nanos > 0)
+                LockSupport.parkNanos(this, nanos);
+            return isReleasable();
+        }
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long stateOffset;
+    static {
+        try {
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = Phaser.class;
+            stateOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("state"));
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java b/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
index cffbe64..26c72eb 100644
--- a/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
+++ b/luni/src/main/java/java/util/concurrent/PriorityBlockingQueue.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -81,7 +81,7 @@
      * java.util.PriorityQueue operations within a lock, as was done
      * in a previous version of this class. To maintain
      * interoperability, a plain PriorityQueue is still used during
-     * serialization, which maintains compatibility at the espense of
+     * serialization, which maintains compatibility at the expense of
      * transiently doubling overhead.
      */
 
@@ -139,7 +139,7 @@
      * to maintain compatibility with previous versions
      * of this class. Non-null only during serialization/deserialization.
      */
-    private PriorityQueue q;
+    private PriorityQueue<E> q;
 
     /**
      * Creates a {@code PriorityBlockingQueue} with the default
@@ -278,14 +278,13 @@
     /**
      * Mechanics for poll().  Call only while holding lock.
      */
-    private E extract() {
-        E result;
+    private E dequeue() {
         int n = size - 1;
         if (n < 0)
-            result = null;
+            return null;
         else {
             Object[] array = queue;
-            result = (E) array[0];
+            E result = (E) array[0];
             E x = (E) array[n];
             array[n] = null;
             Comparator<? super E> cmp = comparator;
@@ -294,8 +293,8 @@
             else
                 siftDownUsingComparator(0, x, array, n, cmp);
             size = n;
+            return result;
         }
-        return result;
     }
 
     /**
@@ -312,6 +311,7 @@
      * @param k the position to fill
      * @param x the item to insert
      * @param array the heap array
+     * @param n heap size
      */
     private static <T> void siftUpComparable(int k, T x, Object[] array) {
         Comparable<? super T> key = (Comparable<? super T>) x;
@@ -476,7 +476,7 @@
      * @param timeout This parameter is ignored as the method never blocks
      * @param unit This parameter is ignored as the method never blocks
      * @return {@code true} (as specified by
-     *  {@link BlockingQueue#offer BlockingQueue.offer})
+     *  {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer})
      * @throws ClassCastException if the specified element cannot be compared
      *         with elements currently in the priority queue according to the
      *         priority queue's ordering
@@ -489,13 +489,11 @@
     public E poll() {
         final ReentrantLock lock = this.lock;
         lock.lock();
-        E result;
         try {
-            result = extract();
+            return dequeue();
         } finally {
             lock.unlock();
         }
-        return result;
     }
 
     public E take() throws InterruptedException {
@@ -503,7 +501,7 @@
         lock.lockInterruptibly();
         E result;
         try {
-            while ( (result = extract()) == null)
+            while ( (result = dequeue()) == null)
                 notEmpty.await();
         } finally {
             lock.unlock();
@@ -517,7 +515,7 @@
         lock.lockInterruptibly();
         E result;
         try {
-            while ( (result = extract()) == null && nanos > 0)
+            while ( (result = dequeue()) == null && nanos > 0)
                 nanos = notEmpty.awaitNanos(nanos);
         } finally {
             lock.unlock();
@@ -528,13 +526,11 @@
     public E peek() {
         final ReentrantLock lock = this.lock;
         lock.lock();
-        E result;
         try {
-            result = size > 0 ? (E) queue[0] : null;
+            return (size == 0) ? null : (E) queue[0];
         } finally {
             lock.unlock();
         }
-        return result;
     }
 
     /**
@@ -618,32 +614,28 @@
      * @return {@code true} if this queue changed as a result of the call
      */
     public boolean remove(Object o) {
-        boolean removed = false;
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
             int i = indexOf(o);
-            if (i != -1) {
-                removeAt(i);
-                removed = true;
-            }
+            if (i == -1)
+                return false;
+            removeAt(i);
+            return true;
         } finally {
             lock.unlock();
         }
-        return removed;
     }
 
-
     /**
      * Identity-based version for use in Itr.remove
      */
-    private void removeEQ(Object o) {
+    void removeEQ(Object o) {
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
             Object[] array = queue;
-            int n = size;
-            for (int i = 0; i < n; i++) {
+            for (int i = 0, n = size; i < n; i++) {
                 if (o == array[i]) {
                     removeAt(i);
                     break;
@@ -663,15 +655,13 @@
      * @return {@code true} if this queue contains the specified element
      */
     public boolean contains(Object o) {
-        int index;
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            index = indexOf(o);
+            return indexOf(o) != -1;
         } finally {
             lock.unlock();
         }
-        return index != -1;
     }
 
     /**
@@ -697,7 +687,6 @@
         }
     }
 
-
     public String toString() {
         final ReentrantLock lock = this.lock;
         lock.lock();
@@ -708,7 +697,7 @@
             StringBuilder sb = new StringBuilder();
             sb.append('[');
             for (int i = 0; i < n; ++i) {
-                E e = (E)queue[i];
+                Object e = queue[i];
                 sb.append(e == this ? "(this Collection)" : e);
                 if (i != n - 1)
                     sb.append(',').append(' ');
@@ -726,23 +715,7 @@
      * @throws IllegalArgumentException      {@inheritDoc}
      */
     public int drainTo(Collection<? super E> c) {
-        if (c == null)
-            throw new NullPointerException();
-        if (c == this)
-            throw new IllegalArgumentException();
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try {
-            int n = 0;
-            E e;
-            while ( (e = extract()) != null) {
-                c.add(e);
-                ++n;
-            }
-            return n;
-        } finally {
-            lock.unlock();
-        }
+        return drainTo(c, Integer.MAX_VALUE);
     }
 
     /**
@@ -761,11 +734,10 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            int n = 0;
-            E e;
-            while (n < maxElements && (e = extract()) != null) {
-                c.add(e);
-                ++n;
+            int n = Math.min(size, maxElements);
+            for (int i = 0; i < n; i++) {
+                c.add((E) queue[0]); // In this order, in case add() throws.
+                dequeue();
             }
             return n;
         } finally {
@@ -813,8 +785,7 @@
      * The following code can be used to dump the queue into a newly
      * allocated array of {@code String}:
      *
-     * <pre>
-     *     String[] y = x.toArray(new String[0]);</pre>
+     *  <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
      *
      * Note that {@code toArray(new Object[0])} is identical in function to
      * {@code toArray()}.
@@ -867,7 +838,7 @@
      */
     final class Itr implements Iterator<E> {
         final Object[] array; // Array of all elements
-        int cursor;           // index of next element to return;
+        int cursor;           // index of next element to return
         int lastRet;          // index of last element, or -1 if no such
 
         Itr(Object[] array) {
@@ -904,8 +875,8 @@
         throws java.io.IOException {
         lock.lock();
         try {
-            int n = size; // avoid zero capacity argument
-            q = new PriorityQueue<E>(n == 0 ? 1 : n, comparator);
+            // avoid zero capacity argument
+            q = new PriorityQueue<E>(Math.max(size, 1), comparator);
             q.addAll(this);
             s.defaultWriteObject();
         } finally {
@@ -933,21 +904,16 @@
     }
 
     // Unsafe mechanics
-    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-    private static final long allocationSpinLockOffset =
-        objectFieldOffset(UNSAFE, "allocationSpinLock",
-                          PriorityBlockingQueue.class);
-
-    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
-                                  String field, Class<?> klazz) {
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long allocationSpinLockOffset;
+    static {
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class<?> k = PriorityBlockingQueue.class;
+            allocationSpinLockOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("allocationSpinLock"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
-
 }
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveAction.java b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
new file mode 100644
index 0000000..48066c9
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
@@ -0,0 +1,165 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A recursive resultless {@link ForkJoinTask}.  This class
+ * establishes conventions to parameterize resultless actions as
+ * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the
+ * only valid value of type {@code Void}, methods such as {@code join}
+ * always return {@code null} upon completion.
+ *
+ * <p><b>Sample Usages.</b> Here is a simple but complete ForkJoin
+ * sort that sorts a given {@code long[]} array:
+ *
+ *  <pre> {@code
+ * static class SortTask extends RecursiveAction {
+ *   final long[] array; final int lo, hi;
+ *   SortTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   SortTask(long[] array) { this(array, 0, array.length); }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD)
+ *       sortSequentially(lo, hi);
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new SortTask(array, lo, mid),
+ *                 new SortTask(array, mid, hi));
+ *       merge(lo, mid, hi);
+ *     }
+ *   }
+ *   // implementation details follow:
+ *   final static int THRESHOLD = 1000;
+ *   void sortSequentially(int lo, int hi) {
+ *     Arrays.sort(array, lo, hi);
+ *   }
+ *   void merge(int lo, int mid, int hi) {
+ *     long[] buf = Arrays.copyOfRange(array, lo, mid);
+ *     for (int i = 0, j = lo, k = mid; i < buf.length; j++)
+ *       array[j] = (k == hi || buf[i] < array[k]) ?
+ *         buf[i++] : array[k++];
+ *   }
+ * }}</pre>
+ *
+ * You could then sort {@code anArray} by creating {@code new
+ * SortTask(anArray)} and invoking it in a ForkJoinPool.  As a more
+ * concrete simple example, the following task increments each element
+ * of an array:
+ *  <pre> {@code
+ * class IncrementTask extends RecursiveAction {
+ *   final long[] array; final int lo, hi;
+ *   IncrementTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD) {
+ *       for (int i = lo; i < hi; ++i)
+ *         array[i]++;
+ *     }
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new IncrementTask(array, lo, mid),
+ *                 new IncrementTask(array, mid, hi));
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>The following example illustrates some refinements and idioms
+ * that may lead to better performance: RecursiveActions need not be
+ * fully recursive, so long as they maintain the basic
+ * divide-and-conquer approach. Here is a class that sums the squares
+ * of each element of a double array, by subdividing out only the
+ * right-hand-sides of repeated divisions by two, and keeping track of
+ * them with a chain of {@code next} references. It uses a dynamic
+ * threshold based on method {@code getSurplusQueuedTaskCount}, but
+ * counterbalances potential excess partitioning by directly
+ * performing leaf actions on unstolen tasks rather than further
+ * subdividing.
+ *
+ *  <pre> {@code
+ * double sumOfSquares(ForkJoinPool pool, double[] array) {
+ *   int n = array.length;
+ *   Applyer a = new Applyer(array, 0, n, null);
+ *   pool.invoke(a);
+ *   return a.result;
+ * }
+ *
+ * class Applyer extends RecursiveAction {
+ *   final double[] array;
+ *   final int lo, hi;
+ *   double result;
+ *   Applyer next; // keeps track of right-hand-side tasks
+ *   Applyer(double[] array, int lo, int hi, Applyer next) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *
+ *   double atLeaf(int l, int h) {
+ *     double sum = 0;
+ *     for (int i = l; i < h; ++i) // perform leftmost base step
+ *       sum += array[i] * array[i];
+ *     return sum;
+ *   }
+ *
+ *   protected void compute() {
+ *     int l = lo;
+ *     int h = hi;
+ *     Applyer right = null;
+ *     while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) {
+ *        int mid = (l + h) >>> 1;
+ *        right = new Applyer(array, mid, h, right);
+ *        right.fork();
+ *        h = mid;
+ *     }
+ *     double sum = atLeaf(l, h);
+ *     while (right != null) {
+ *        if (right.tryUnfork()) // directly calculate if not stolen
+ *          sum += right.atLeaf(right.lo, right.hi);
+ *       else {
+ *          right.join();
+ *          sum += right.result;
+ *        }
+ *        right = right.next;
+ *      }
+ *     result = sum;
+ *   }
+ * }}</pre>
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ */
+public abstract class RecursiveAction extends ForkJoinTask<Void> {
+    private static final long serialVersionUID = 5232453952276485070L;
+
+    /**
+     * The main computation performed by this task.
+     */
+    protected abstract void compute();
+
+    /**
+     * Always returns {@code null}.
+     *
+     * @return {@code null} always
+     */
+    public final Void getRawResult() { return null; }
+
+    /**
+     * Requires null completion value.
+     */
+    protected final void setRawResult(Void mustBeNull) { }
+
+    /**
+     * Implements execution conventions for RecursiveActions.
+     */
+    protected final boolean exec() {
+        compute();
+        return true;
+    }
+
+}
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveTask.java b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
new file mode 100644
index 0000000..5e17280
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
@@ -0,0 +1,69 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A recursive result-bearing {@link ForkJoinTask}.
+ *
+ * <p>For a classic example, here is a task computing Fibonacci numbers:
+ *
+ *  <pre> {@code
+ * class Fibonacci extends RecursiveTask<Integer> {
+ *   final int n;
+ *   Fibonacci(int n) { this.n = n; }
+ *   Integer compute() {
+ *     if (n <= 1)
+ *        return n;
+ *     Fibonacci f1 = new Fibonacci(n - 1);
+ *     f1.fork();
+ *     Fibonacci f2 = new Fibonacci(n - 2);
+ *     return f2.compute() + f1.join();
+ *   }
+ * }}</pre>
+ *
+ * However, besides being a dumb way to compute Fibonacci functions
+ * (there is a simple fast linear algorithm that you'd use in
+ * practice), this is likely to perform poorly because the smallest
+ * subtasks are too small to be worthwhile splitting up. Instead, as
+ * is the case for nearly all fork/join applications, you'd pick some
+ * minimum granularity size (for example 10 here) for which you always
+ * sequentially solve rather than subdividing.
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ */
+public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
+    private static final long serialVersionUID = 5232453952276485270L;
+
+    /**
+     * The result of the computation.
+     */
+    V result;
+
+    /**
+     * The main computation performed by this task.
+     */
+    protected abstract V compute();
+
+    public final V getRawResult() {
+        return result;
+    }
+
+    protected final void setRawResult(V value) {
+        result = value;
+    }
+
+    /**
+     * Implements execution conventions for RecursiveTask.
+     */
+    protected final boolean exec() {
+        result = compute();
+        return true;
+    }
+
+}
diff --git a/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java b/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java
index 30b043d..f0005d1 100644
--- a/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java
+++ b/luni/src/main/java/java/util/concurrent/RejectedExecutionException.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -49,8 +49,8 @@
 
     /**
      * Constructs a <tt>RejectedExecutionException</tt> with the
-     * specified cause.  The detail message is set to: <pre> (cause ==
-     * null ? null : cause.toString())</pre> (which typically contains
+     * specified cause.  The detail message is set to {@code (cause ==
+     * null ? null : cause.toString())} (which typically contains
      * the class and detail message of <tt>cause</tt>).
      *
      * @param  cause the cause (which is saved for later retrieval by the
diff --git a/luni/src/main/java/java/util/concurrent/RejectedExecutionHandler.java b/luni/src/main/java/java/util/concurrent/RejectedExecutionHandler.java
index 417a27c..8c000ea 100644
--- a/luni/src/main/java/java/util/concurrent/RejectedExecutionHandler.java
+++ b/luni/src/main/java/java/util/concurrent/RejectedExecutionHandler.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/RunnableFuture.java b/luni/src/main/java/java/util/concurrent/RunnableFuture.java
index d74211d..2d6d52c 100644
--- a/luni/src/main/java/java/util/concurrent/RunnableFuture.java
+++ b/luni/src/main/java/java/util/concurrent/RunnableFuture.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java b/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
index 0e8cc32..fbb995c 100644
--- a/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
+++ b/luni/src/main/java/java/util/concurrent/RunnableScheduledFuture.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java b/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
index 6cb4e27..71e57ed 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledExecutorService.java
@@ -1,12 +1,10 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
-import java.util.concurrent.atomic.*;
-import java.util.*;
 
 /**
  * An {@link ExecutorService} that can schedule commands to run after a given
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledFuture.java b/luni/src/main/java/java/util/concurrent/ScheduledFuture.java
index 239d681..3745cb0 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledFuture.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledFuture.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index c2eaedf..e41f0c3 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -1,16 +1,19 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
-import java.util.concurrent.atomic.*;
-import java.util.concurrent.locks.*;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.*;
 
 // BEGIN android-note
-// Omit class-level docs on setRemoveOnCancelPolicy()
+// omit class-level docs on setRemoveOnCancelPolicy()
+// removed security manager docs
 // END android-note
 
 /**
@@ -138,7 +141,7 @@
      * Sequence number to break scheduling ties, and in turn to
      * guarantee FIFO order among tied entries.
      */
-    private static final AtomicLong sequencer = new AtomicLong(0);
+    private static final AtomicLong sequencer = new AtomicLong();
 
     /**
      * Returns current nanosecond time.
@@ -203,11 +206,11 @@
         }
 
         public long getDelay(TimeUnit unit) {
-            return unit.convert(time - now(), TimeUnit.NANOSECONDS);
+            return unit.convert(time - now(), NANOSECONDS);
         }
 
         public int compareTo(Delayed other) {
-            if (other == this) // compare zero ONLY if same object
+            if (other == this) // compare zero if same object
                 return 0;
             if (other instanceof ScheduledFutureTask) {
                 ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
@@ -221,9 +224,9 @@
                 else
                     return 1;
             }
-            long d = (getDelay(TimeUnit.NANOSECONDS) -
-                      other.getDelay(TimeUnit.NANOSECONDS));
-            return (d == 0) ? 0 : ((d < 0) ? -1 : 1);
+            long diff = (getDelay(NANOSECONDS) -
+                         other.getDelay(NANOSECONDS));
+            return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
         }
 
         /**
@@ -302,7 +305,7 @@
                 remove(task))
                 task.cancel(false);
             else
-                prestartCoreThread();
+                ensurePrestart();
         }
     }
 
@@ -318,7 +321,7 @@
             if (!canRunInCurrentRunState(true) && remove(task))
                 task.cancel(false);
             else
-                prestartCoreThread();
+                ensurePrestart();
         }
     }
 
@@ -396,7 +399,7 @@
      * @throws IllegalArgumentException if {@code corePoolSize < 0}
      */
     public ScheduledThreadPoolExecutor(int corePoolSize) {
-        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
+        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
               new DelayedWorkQueue());
     }
 
@@ -413,7 +416,7 @@
      */
     public ScheduledThreadPoolExecutor(int corePoolSize,
                                        ThreadFactory threadFactory) {
-        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
+        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
               new DelayedWorkQueue(), threadFactory);
     }
 
@@ -430,7 +433,7 @@
      */
     public ScheduledThreadPoolExecutor(int corePoolSize,
                                        RejectedExecutionHandler handler) {
-        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
+        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
               new DelayedWorkQueue(), handler);
     }
 
@@ -451,7 +454,7 @@
     public ScheduledThreadPoolExecutor(int corePoolSize,
                                        ThreadFactory threadFactory,
                                        RejectedExecutionHandler handler) {
-        super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
+        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
               new DelayedWorkQueue(), threadFactory, handler);
     }
 
@@ -480,7 +483,7 @@
     private long overflowFree(long delay) {
         Delayed head = (Delayed) super.getQueue().peek();
         if (head != null) {
-            long headDelay = head.getDelay(TimeUnit.NANOSECONDS);
+            long headDelay = head.getDelay(NANOSECONDS);
             if (headDelay < 0 && (delay - headDelay < 0))
                 delay = Long.MAX_VALUE + headDelay;
         }
@@ -588,7 +591,7 @@
      * @throws NullPointerException {@inheritDoc}
      */
     public void execute(Runnable command) {
-        schedule(command, 0, TimeUnit.NANOSECONDS);
+        schedule(command, 0, NANOSECONDS);
     }
 
     // Override AbstractExecutorService methods
@@ -598,7 +601,7 @@
      * @throws NullPointerException       {@inheritDoc}
      */
     public Future<?> submit(Runnable task) {
-        return schedule(task, 0, TimeUnit.NANOSECONDS);
+        return schedule(task, 0, NANOSECONDS);
     }
 
     /**
@@ -606,8 +609,7 @@
      * @throws NullPointerException       {@inheritDoc}
      */
     public <T> Future<T> submit(Runnable task, T result) {
-        return schedule(Executors.callable(task, result),
-                        0, TimeUnit.NANOSECONDS);
+        return schedule(Executors.callable(task, result), 0, NANOSECONDS);
     }
 
     /**
@@ -615,7 +617,7 @@
      * @throws NullPointerException       {@inheritDoc}
      */
     public <T> Future<T> submit(Callable<T> task) {
-        return schedule(task, 0, TimeUnit.NANOSECONDS);
+        return schedule(task, 0, NANOSECONDS);
     }
 
     /**
@@ -690,8 +692,9 @@
      * @param value if {@code true}, remove on cancellation, else don't
      * @see #getRemoveOnCancelPolicy
      * @since 1.7
+     * @hide
      */
-    /*public*/ void setRemoveOnCancelPolicy(boolean value) { // android-changed
+    public void setRemoveOnCancelPolicy(boolean value) {
         removeOnCancel = value;
     }
 
@@ -704,8 +707,9 @@
      *         from the queue
      * @see #setRemoveOnCancelPolicy
      * @since 1.7
+     * @hide
      */
-    /*public*/ boolean getRemoveOnCancelPolicy() { // android-changed
+    public boolean getRemoveOnCancelPolicy() {
         return removeOnCancel;
     }
 
@@ -724,8 +728,6 @@
      * ContinueExistingPeriodicTasksAfterShutdownPolicy} has been set
      * {@code true}, future executions of existing periodic tasks will
      * be cancelled.
-     *
-     * @throws SecurityException {@inheritDoc}
      */
     public void shutdown() {
         super.shutdown();
@@ -750,7 +752,6 @@
      *         including those tasks submitted using {@code execute},
      *         which are for scheduling purposes used as the basis of a
      *         zero-delay {@code ScheduledFuture}.
-     * @throws SecurityException {@inheritDoc}
      */
     public List<Runnable> shutdownNow() {
         return super.shutdownNow();
@@ -803,8 +804,8 @@
          */
 
         private static final int INITIAL_CAPACITY = 16;
-        private RunnableScheduledFuture[] queue =
-            new RunnableScheduledFuture[INITIAL_CAPACITY];
+        private RunnableScheduledFuture<?>[] queue =
+            new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
         private final ReentrantLock lock = new ReentrantLock();
         private int size = 0;
 
@@ -835,7 +836,7 @@
         /**
          * Set f's heapIndex if it is a ScheduledFutureTask.
          */
-        private void setIndex(RunnableScheduledFuture f, int idx) {
+        private void setIndex(RunnableScheduledFuture<?> f, int idx) {
             if (f instanceof ScheduledFutureTask)
                 ((ScheduledFutureTask)f).heapIndex = idx;
         }
@@ -844,10 +845,10 @@
          * Sift element added at bottom up to its heap-ordered spot.
          * Call only when holding lock.
          */
-        private void siftUp(int k, RunnableScheduledFuture key) {
+        private void siftUp(int k, RunnableScheduledFuture<?> key) {
             while (k > 0) {
                 int parent = (k - 1) >>> 1;
-                RunnableScheduledFuture e = queue[parent];
+                RunnableScheduledFuture<?> e = queue[parent];
                 if (key.compareTo(e) >= 0)
                     break;
                 queue[k] = e;
@@ -862,11 +863,11 @@
          * Sift element added at top down to its heap-ordered spot.
          * Call only when holding lock.
          */
-        private void siftDown(int k, RunnableScheduledFuture key) {
+        private void siftDown(int k, RunnableScheduledFuture<?> key) {
             int half = size >>> 1;
             while (k < half) {
                 int child = (k << 1) + 1;
-                RunnableScheduledFuture c = queue[child];
+                RunnableScheduledFuture<?> c = queue[child];
                 int right = child + 1;
                 if (right < size && c.compareTo(queue[right]) > 0)
                     c = queue[child = right];
@@ -931,7 +932,7 @@
 
                 setIndex(queue[i], -1);
                 int s = --size;
-                RunnableScheduledFuture replacement = queue[s];
+                RunnableScheduledFuture<?> replacement = queue[s];
                 queue[s] = null;
                 if (s != i) {
                     siftDown(i, replacement);
@@ -962,7 +963,7 @@
             return Integer.MAX_VALUE;
         }
 
-        public RunnableScheduledFuture peek() {
+        public RunnableScheduledFuture<?> peek() {
             final ReentrantLock lock = this.lock;
             lock.lock();
             try {
@@ -975,7 +976,7 @@
         public boolean offer(Runnable x) {
             if (x == null)
                 throw new NullPointerException();
-            RunnableScheduledFuture e = (RunnableScheduledFuture)x;
+            RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>)x;
             final ReentrantLock lock = this.lock;
             lock.lock();
             try {
@@ -1017,9 +1018,9 @@
          * holding lock.
          * @param f the task to remove and return
          */
-        private RunnableScheduledFuture finishPoll(RunnableScheduledFuture f) {
+        private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
             int s = --size;
-            RunnableScheduledFuture x = queue[s];
+            RunnableScheduledFuture<?> x = queue[s];
             queue[s] = null;
             if (s != 0)
                 siftDown(0, x);
@@ -1027,12 +1028,12 @@
             return f;
         }
 
-        public RunnableScheduledFuture poll() {
+        public RunnableScheduledFuture<?> poll() {
             final ReentrantLock lock = this.lock;
             lock.lock();
             try {
-                RunnableScheduledFuture first = queue[0];
-                if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
+                RunnableScheduledFuture<?> first = queue[0];
+                if (first == null || first.getDelay(NANOSECONDS) > 0)
                     return null;
                 else
                     return finishPoll(first);
@@ -1041,16 +1042,16 @@
             }
         }
 
-        public RunnableScheduledFuture take() throws InterruptedException {
+        public RunnableScheduledFuture<?> take() throws InterruptedException {
             final ReentrantLock lock = this.lock;
             lock.lockInterruptibly();
             try {
                 for (;;) {
-                    RunnableScheduledFuture first = queue[0];
+                    RunnableScheduledFuture<?> first = queue[0];
                     if (first == null)
                         available.await();
                     else {
-                        long delay = first.getDelay(TimeUnit.NANOSECONDS);
+                        long delay = first.getDelay(NANOSECONDS);
                         if (delay <= 0)
                             return finishPoll(first);
                         else if (leader != null)
@@ -1074,21 +1075,21 @@
             }
         }
 
-        public RunnableScheduledFuture poll(long timeout, TimeUnit unit)
+        public RunnableScheduledFuture<?> poll(long timeout, TimeUnit unit)
             throws InterruptedException {
             long nanos = unit.toNanos(timeout);
             final ReentrantLock lock = this.lock;
             lock.lockInterruptibly();
             try {
                 for (;;) {
-                    RunnableScheduledFuture first = queue[0];
+                    RunnableScheduledFuture<?> first = queue[0];
                     if (first == null) {
                         if (nanos <= 0)
                             return null;
                         else
                             nanos = available.awaitNanos(nanos);
                     } else {
-                        long delay = first.getDelay(TimeUnit.NANOSECONDS);
+                        long delay = first.getDelay(NANOSECONDS);
                         if (delay <= 0)
                             return finishPoll(first);
                         if (nanos <= 0)
@@ -1120,7 +1121,7 @@
             lock.lock();
             try {
                 for (int i = 0; i < size; i++) {
-                    RunnableScheduledFuture t = queue[i];
+                    RunnableScheduledFuture<?> t = queue[i];
                     if (t != null) {
                         queue[i] = null;
                         setIndex(t, -1);
@@ -1133,14 +1134,14 @@
         }
 
         /**
-         * Return and remove first element only if it is expired.
+         * Return first element only if it is expired.
          * Used only by drainTo.  Call only when holding lock.
          */
-        private RunnableScheduledFuture pollExpired() {
-            RunnableScheduledFuture first = queue[0];
-            if (first == null || first.getDelay(TimeUnit.NANOSECONDS) > 0)
-                return null;
-            return finishPoll(first);
+        private RunnableScheduledFuture<?> peekExpired() {
+            // assert lock.isHeldByCurrentThread();
+            RunnableScheduledFuture<?> first = queue[0];
+            return (first == null || first.getDelay(NANOSECONDS) > 0) ?
+                null : first;
         }
 
         public int drainTo(Collection<? super Runnable> c) {
@@ -1151,10 +1152,11 @@
             final ReentrantLock lock = this.lock;
             lock.lock();
             try {
-                RunnableScheduledFuture first;
+                RunnableScheduledFuture<?> first;
                 int n = 0;
-                while ((first = pollExpired()) != null) {
-                    c.add(first);
+                while ((first = peekExpired()) != null) {
+                    c.add(first);   // In this order, in case add() throws.
+                    finishPoll(first);
                     ++n;
                 }
                 return n;
@@ -1173,10 +1175,11 @@
             final ReentrantLock lock = this.lock;
             lock.lock();
             try {
-                RunnableScheduledFuture first;
+                RunnableScheduledFuture<?> first;
                 int n = 0;
-                while (n < maxElements && (first = pollExpired()) != null) {
-                    c.add(first);
+                while (n < maxElements && (first = peekExpired()) != null) {
+                    c.add(first);   // In this order, in case add() throws.
+                    finishPoll(first);
                     ++n;
                 }
                 return n;
diff --git a/luni/src/main/java/java/util/concurrent/Semaphore.java b/luni/src/main/java/java/util/concurrent/Semaphore.java
index 62dea1a..bf2524c 100644
--- a/luni/src/main/java/java/util/concurrent/Semaphore.java
+++ b/luni/src/main/java/java/util/concurrent/Semaphore.java
@@ -1,13 +1,12 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
 import java.util.*;
 import java.util.concurrent.locks.*;
-import java.util.concurrent.atomic.*;
 
 /**
  * A counting semaphore.  Conceptually, a semaphore maintains a set of
@@ -20,7 +19,7 @@
  * <p>Semaphores are often used to restrict the number of threads than can
  * access some (physical or logical) resource. For example, here is
  * a class that uses a semaphore to control access to a pool of items:
- * <pre>
+ *  <pre> {@code
  * class Pool {
  *   private static final int MAX_AVAILABLE = 100;
  *   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
@@ -62,9 +61,7 @@
  *     }
  *     return false;
  *   }
- *
- * }
- * </pre>
+ * }}</pre>
  *
  * <p>Before obtaining an item each thread must acquire a permit from
  * the semaphore, guaranteeing that an item is available for use. When
diff --git a/luni/src/main/java/java/util/concurrent/SynchronousQueue.java b/luni/src/main/java/java/util/concurrent/SynchronousQueue.java
index 51d40c0..b05ae0a 100644
--- a/luni/src/main/java/java/util/concurrent/SynchronousQueue.java
+++ b/luni/src/main/java/java/util/concurrent/SynchronousQueue.java
@@ -2,13 +2,12 @@
  * Written by Doug Lea, Bill Scherer, and Michael Scott with
  * assistance from members of JCP JSR-166 Expert Group and released to
  * the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
 import java.util.concurrent.locks.*;
 import java.util.*;
-import libcore.util.EmptyArray;
 
 // BEGIN android-note
 // removed link to collections framework docs
@@ -250,12 +249,22 @@
             }
 
             // Unsafe mechanics
-            private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-            private static final long nextOffset =
-                objectFieldOffset(UNSAFE, "next", SNode.class);
-            private static final long matchOffset =
-                objectFieldOffset(UNSAFE, "match", SNode.class);
+            private static final sun.misc.Unsafe UNSAFE;
+            private static final long matchOffset;
+            private static final long nextOffset;
 
+            static {
+                try {
+                    UNSAFE = sun.misc.Unsafe.getUnsafe();
+                    Class<?> k = SNode.class;
+                    matchOffset = UNSAFE.objectFieldOffset
+                        (k.getDeclaredField("match"));
+                    nextOffset = UNSAFE.objectFieldOffset
+                        (k.getDeclaredField("next"));
+                } catch (Exception e) {
+                    throw new Error(e);
+                }
+            }
         }
 
         /** The head (top) of the stack */
@@ -393,7 +402,6 @@
              */
             long lastTime = timed ? System.nanoTime() : 0;
             Thread w = Thread.currentThread();
-            SNode h = head;
             int spins = (shouldSpin(s) ?
                          (timed ? maxTimedSpins : maxUntimedSpins) : 0);
             for (;;) {
@@ -469,10 +477,18 @@
         }
 
         // Unsafe mechanics
-        private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-        private static final long headOffset =
-            objectFieldOffset(UNSAFE, "head", TransferStack.class);
-
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long headOffset;
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class<?> k = TransferStack.class;
+                headOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("head"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /** Dual Queue */
@@ -529,11 +545,22 @@
             }
 
             // Unsafe mechanics
-            private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-            private static final long nextOffset =
-                objectFieldOffset(UNSAFE, "next", QNode.class);
-            private static final long itemOffset =
-                objectFieldOffset(UNSAFE, "item", QNode.class);
+            private static final sun.misc.Unsafe UNSAFE;
+            private static final long itemOffset;
+            private static final long nextOffset;
+
+            static {
+                try {
+                    UNSAFE = sun.misc.Unsafe.getUnsafe();
+                    Class<?> k = QNode.class;
+                    itemOffset = UNSAFE.objectFieldOffset
+                        (k.getDeclaredField("item"));
+                    nextOffset = UNSAFE.objectFieldOffset
+                        (k.getDeclaredField("next"));
+                } catch (Exception e) {
+                    throw new Error(e);
+                }
+            }
         }
 
         /** Head of queue */
@@ -762,15 +789,24 @@
             }
         }
 
-        // unsafe mechanics
-        private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-        private static final long headOffset =
-            objectFieldOffset(UNSAFE, "head", TransferQueue.class);
-        private static final long tailOffset =
-            objectFieldOffset(UNSAFE, "tail", TransferQueue.class);
-        private static final long cleanMeOffset =
-            objectFieldOffset(UNSAFE, "cleanMe", TransferQueue.class);
-
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long headOffset;
+        private static final long tailOffset;
+        private static final long cleanMeOffset;
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class<?> k = TransferQueue.class;
+                headOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("head"));
+                tailOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("tail"));
+                cleanMeOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("cleanMe"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /**
@@ -998,8 +1034,19 @@
      *
      * @return an empty iterator
      */
+    @SuppressWarnings("unchecked")
     public Iterator<E> iterator() {
-        return Collections.<E>emptySet().iterator(); // android-changed
+        return (Iterator<E>) EmptyIterator.EMPTY_ITERATOR;
+    }
+
+    // Replicated from a previous version of Collections
+    private static class EmptyIterator<E> implements Iterator<E> {
+        static final EmptyIterator<Object> EMPTY_ITERATOR
+            = new EmptyIterator<Object>();
+
+        public boolean hasNext() { return false; }
+        public E next() { throw new NoSuchElementException(); }
+        public void remove() { throw new IllegalStateException(); }
     }
 
     /**
@@ -1007,7 +1054,7 @@
      * @return a zero-length array
      */
     public Object[] toArray() {
-        return EmptyArray.OBJECT; // android-changed
+        return new Object[0];
     }
 
     /**
@@ -1036,8 +1083,7 @@
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        E e;
-        while ( (e = poll()) != null) {
+        for (E e; (e = poll()) != null;) {
             c.add(e);
             ++n;
         }
@@ -1056,8 +1102,7 @@
         if (c == this)
             throw new IllegalArgumentException();
         int n = 0;
-        E e;
-        while (n < maxElements && (e = poll()) != null) {
+        for (E e; n < maxElements && (e = poll()) != null;) {
             c.add(e);
             ++n;
         }
@@ -1084,7 +1129,7 @@
     private WaitQueue waitingConsumers;
 
     /**
-     * Save the state to a stream (that is, serialize it).
+     * Saves the state to a stream (that is, serializes it).
      *
      * @param s the stream
      */
diff --git a/luni/src/main/java/java/util/concurrent/ThreadFactory.java b/luni/src/main/java/java/util/concurrent/ThreadFactory.java
index 2f0fb1a..d1a4eb6 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadFactory.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadFactory.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -13,13 +13,12 @@
  *
  * <p>
  * The simplest implementation of this interface is just:
- * <pre>
+ *  <pre> {@code
  * class SimpleThreadFactory implements ThreadFactory {
  *   public Thread newThread(Runnable r) {
  *     return new Thread(r);
  *   }
- * }
- * </pre>
+ * }}</pre>
  *
  * The {@link Executors#defaultThreadFactory} method provides a more
  * useful simple implementation, that sets the created thread context
diff --git a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
new file mode 100644
index 0000000..a559321
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
@@ -0,0 +1,198 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Random;
+
+/**
+ * A random number generator isolated to the current thread.  Like the
+ * global {@link java.util.Random} generator used by the {@link
+ * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized
+ * with an internally generated seed that may not otherwise be
+ * modified. When applicable, use of {@code ThreadLocalRandom} rather
+ * than shared {@code Random} objects in concurrent programs will
+ * typically encounter much less overhead and contention.  Use of
+ * {@code ThreadLocalRandom} is particularly appropriate when multiple
+ * tasks (for example, each a {@link ForkJoinTask}) use random numbers
+ * in parallel in thread pools.
+ *
+ * <p>Usages of this class should typically be of the form:
+ * {@code ThreadLocalRandom.current().nextX(...)} (where
+ * {@code X} is {@code Int}, {@code Long}, etc).
+ * When all usages are of this form, it is never possible to
+ * accidently share a {@code ThreadLocalRandom} across multiple threads.
+ *
+ * <p>This class also provides additional commonly used bounded random
+ * generation methods.
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ */
+public class ThreadLocalRandom extends Random {
+    // same constants as Random, but must be redeclared because private
+    private static final long multiplier = 0x5DEECE66DL;
+    private static final long addend = 0xBL;
+    private static final long mask = (1L << 48) - 1;
+
+    /**
+     * The random seed. We can't use super.seed.
+     */
+    private long rnd;
+
+    /**
+     * Initialization flag to permit calls to setSeed to succeed only
+     * while executing the Random constructor.  We can't allow others
+     * since it would cause setting seed in one part of a program to
+     * unintentionally impact other usages by the thread.
+     */
+    boolean initialized;
+
+    // Padding to help avoid memory contention among seed updates in
+    // different TLRs in the common case that they are located near
+    // each other.
+    private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
+
+    /**
+     * The actual ThreadLocal
+     */
+    private static final ThreadLocal<ThreadLocalRandom> localRandom =
+        new ThreadLocal<ThreadLocalRandom>() {
+            protected ThreadLocalRandom initialValue() {
+                return new ThreadLocalRandom();
+            }
+    };
+
+
+    /**
+     * Constructor called only by localRandom.initialValue.
+     */
+    ThreadLocalRandom() {
+        super();
+        initialized = true;
+    }
+
+    /**
+     * Returns the current thread's {@code ThreadLocalRandom}.
+     *
+     * @return the current thread's {@code ThreadLocalRandom}
+     */
+    public static ThreadLocalRandom current() {
+        return localRandom.get();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}.  Setting seeds in
+     * this generator is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    public void setSeed(long seed) {
+        if (initialized)
+            throw new UnsupportedOperationException();
+        rnd = (seed ^ multiplier) & mask;
+    }
+
+    protected int next(int bits) {
+        rnd = (rnd * multiplier + addend) & mask;
+        return (int) (rnd >>> (48-bits));
+    }
+
+    /**
+     * Returns a pseudorandom, uniformly distributed value between the
+     * given least value (inclusive) and bound (exclusive).
+     *
+     * @param least the least value returned
+     * @param bound the upper bound (exclusive)
+     * @throws IllegalArgumentException if least greater than or equal
+     * to bound
+     * @return the next value
+     */
+    public int nextInt(int least, int bound) {
+        if (least >= bound)
+            throw new IllegalArgumentException();
+        return nextInt(bound - least) + least;
+    }
+
+    /**
+     * Returns a pseudorandom, uniformly distributed value
+     * between 0 (inclusive) and the specified value (exclusive).
+     *
+     * @param n the bound on the random number to be returned.  Must be
+     *        positive.
+     * @return the next value
+     * @throws IllegalArgumentException if n is not positive
+     */
+    public long nextLong(long n) {
+        if (n <= 0)
+            throw new IllegalArgumentException("n must be positive");
+        // Divide n by two until small enough for nextInt. On each
+        // iteration (at most 31 of them but usually much less),
+        // randomly choose both whether to include high bit in result
+        // (offset) and whether to continue with the lower vs upper
+        // half (which makes a difference only if odd).
+        long offset = 0;
+        while (n >= Integer.MAX_VALUE) {
+            int bits = next(2);
+            long half = n >>> 1;
+            long nextn = ((bits & 2) == 0) ? half : n - half;
+            if ((bits & 1) == 0)
+                offset += n - nextn;
+            n = nextn;
+        }
+        return offset + nextInt((int) n);
+    }
+
+    /**
+     * Returns a pseudorandom, uniformly distributed value between the
+     * given least value (inclusive) and bound (exclusive).
+     *
+     * @param least the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return the next value
+     * @throws IllegalArgumentException if least greater than or equal
+     * to bound
+     */
+    public long nextLong(long least, long bound) {
+        if (least >= bound)
+            throw new IllegalArgumentException();
+        return nextLong(bound - least) + least;
+    }
+
+    /**
+     * Returns a pseudorandom, uniformly distributed {@code double} value
+     * between 0 (inclusive) and the specified value (exclusive).
+     *
+     * @param n the bound on the random number to be returned.  Must be
+     *        positive.
+     * @return the next value
+     * @throws IllegalArgumentException if n is not positive
+     */
+    public double nextDouble(double n) {
+        if (n <= 0)
+            throw new IllegalArgumentException("n must be positive");
+        return nextDouble() * n;
+    }
+
+    /**
+     * Returns a pseudorandom, uniformly distributed value between the
+     * given least value (inclusive) and bound (exclusive).
+     *
+     * @param least the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return the next value
+     * @throws IllegalArgumentException if least greater than or equal
+     * to bound
+     */
+    public double nextDouble(double least, double bound) {
+        if (least >= bound)
+            throw new IllegalArgumentException();
+        return nextDouble() * (bound - least) + least;
+    }
+
+    private static final long serialVersionUID = -5851777807851030925L;
+}
diff --git a/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
index 6622af8..331e225 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -9,6 +9,10 @@
 import java.util.concurrent.atomic.*;
 import java.util.*;
 
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
 /**
  * An {@link ExecutorService} that executes each submitted task using
  * one of possibly several pooled threads, normally configured
@@ -1311,8 +1315,6 @@
      * <p>This method does not wait for previously submitted tasks to
      * complete execution.  Use {@link #awaitTermination awaitTermination}
      * to do that.
-     *
-     * @throws SecurityException {@inheritDoc}
      */
     public void shutdown() {
         final ReentrantLock mainLock = this.mainLock;
@@ -1342,8 +1344,6 @@
      * processing actively executing tasks.  This implementation
      * cancels tasks via {@link Thread#interrupt}, so any task that
      * fails to respond to interrupts may never terminate.
-     *
-     * @throws SecurityException {@inheritDoc}
      */
     public List<Runnable> shutdownNow() {
         List<Runnable> tasks;
@@ -1512,6 +1512,18 @@
     }
 
     /**
+     * Same as prestartCoreThread except arranges that at least one
+     * thread is started even if corePoolSize is 0.
+     */
+    void ensurePrestart() {
+        int wc = workerCountOf(ctl.get());
+        if (wc < corePoolSize)
+            addWorker(null, true);
+        else if (wc == 0)
+            addWorker(null, false);
+    }
+
+    /**
      * Starts all core threads, causing them to idly wait for work. This
      * overrides the default policy of starting core threads only when
      * new tasks are executed.
diff --git a/luni/src/main/java/java/util/concurrent/TimeUnit.java b/luni/src/main/java/java/util/concurrent/TimeUnit.java
index b2e3060..50f6ce0 100644
--- a/luni/src/main/java/java/util/concurrent/TimeUnit.java
+++ b/luni/src/main/java/java/util/concurrent/TimeUnit.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
@@ -23,14 +23,14 @@
  * the following code will timeout in 50 milliseconds if the {@link
  * java.util.concurrent.locks.Lock lock} is not available:
  *
- * <pre>  Lock lock = ...;
- *  if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...
- * </pre>
+ *  <pre> {@code
+ * Lock lock = ...;
+ * if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...}</pre>
+ *
  * while this code will timeout in 50 seconds:
- * <pre>
- *  Lock lock = ...;
- *  if (lock.tryLock(50L, TimeUnit.SECONDS)) ...
- * </pre>
+ *  <pre> {@code
+ * Lock lock = ...;
+ * if (lock.tryLock(50L, TimeUnit.SECONDS)) ...}</pre>
  *
  * Note however, that there is no guarantee that a particular timeout
  * implementation will be able to notice the passage of time at the
diff --git a/luni/src/main/java/java/util/concurrent/TimeoutException.java b/luni/src/main/java/java/util/concurrent/TimeoutException.java
index 8b84f28..83934f0 100644
--- a/luni/src/main/java/java/util/concurrent/TimeoutException.java
+++ b/luni/src/main/java/java/util/concurrent/TimeoutException.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent;
diff --git a/luni/src/main/java/java/util/concurrent/TransferQueue.java b/luni/src/main/java/java/util/concurrent/TransferQueue.java
new file mode 100644
index 0000000..9cd5773
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/TransferQueue.java
@@ -0,0 +1,133 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@link BlockingQueue} in which producers may wait for consumers
+ * to receive elements.  A {@code TransferQueue} may be useful for
+ * example in message passing applications in which producers
+ * sometimes (using method {@link #transfer}) await receipt of
+ * elements by consumers invoking {@code take} or {@code poll}, while
+ * at other times enqueue elements (via method {@code put}) without
+ * waiting for receipt.
+ * {@linkplain #tryTransfer(Object) Non-blocking} and
+ * {@linkplain #tryTransfer(Object,long,TimeUnit) time-out} versions of
+ * {@code tryTransfer} are also available.
+ * A {@code TransferQueue} may also be queried, via {@link
+ * #hasWaitingConsumer}, whether there are any threads waiting for
+ * items, which is a converse analogy to a {@code peek} operation.
+ *
+ * <p>Like other blocking queues, a {@code TransferQueue} may be
+ * capacity bounded.  If so, an attempted transfer operation may
+ * initially block waiting for available space, and/or subsequently
+ * block waiting for reception by a consumer.  Note that in a queue
+ * with zero capacity, such as {@link SynchronousQueue}, {@code put}
+ * and {@code transfer} are effectively synonymous.
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ * @param <E> the type of elements held in this collection
+ */
+public interface TransferQueue<E> extends BlockingQueue<E> {
+    /**
+     * Transfers the element to a waiting consumer immediately, if possible.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * otherwise returning {@code false} without enqueuing the element.
+     *
+     * @param e the element to transfer
+     * @return {@code true} if the element was transferred, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean tryTransfer(E e);
+
+    /**
+     * Transfers the element to a consumer, waiting if necessary to do so.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else waits until the element is received by a consumer.
+     *
+     * @param e the element to transfer
+     * @throws InterruptedException if interrupted while waiting,
+     *         in which case the element is not left enqueued
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    void transfer(E e) throws InterruptedException;
+
+    /**
+     * Transfers the element to a consumer if it is possible to do so
+     * before the timeout elapses.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else waits until the element is received by a consumer,
+     * returning {@code false} if the specified wait time elapses
+     * before the element can be transferred.
+     *
+     * @param e the element to transfer
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before completion,
+     *         in which case the element is not left enqueued
+     * @throws InterruptedException if interrupted while waiting,
+     *         in which case the element is not left enqueued
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean tryTransfer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Returns {@code true} if there is at least one consumer waiting
+     * to receive an element via {@link #take} or
+     * timed {@link #poll(long,TimeUnit) poll}.
+     * The return value represents a momentary state of affairs.
+     *
+     * @return {@code true} if there is at least one waiting consumer
+     */
+    boolean hasWaitingConsumer();
+
+    /**
+     * Returns an estimate of the number of consumers waiting to
+     * receive elements via {@link #take} or timed
+     * {@link #poll(long,TimeUnit) poll}.  The return value is an
+     * approximation of a momentary state of affairs, that may be
+     * inaccurate if consumers have completed or given up waiting.
+     * The value may be useful for monitoring and heuristics, but
+     * not for synchronization control.  Implementations of this
+     * method are likely to be noticeably slower than those for
+     * {@link #hasWaitingConsumer}.
+     *
+     * @return the number of consumers waiting to receive elements
+     */
+    int getWaitingConsumerCount();
+}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
index c774d21..d531f25 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
@@ -21,14 +21,14 @@
 public class AtomicBoolean implements java.io.Serializable {
     private static final long serialVersionUID = 4654671469794556979L;
     // setup to use Unsafe.compareAndSwapInt for updates
-    private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static final long valueOffset;
 
     static {
-      try {
-        valueOffset = unsafe.objectFieldOffset
-            (AtomicBoolean.class.getDeclaredField("value"));
-      } catch (Exception ex) { throw new Error(ex); }
+        try {
+            valueOffset = unsafe.objectFieldOffset
+                (AtomicBoolean.class.getDeclaredField("value"));
+        } catch (Exception ex) { throw new Error(ex); }
     }
 
     private volatile int value;
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
index 16dd568..e0a0018 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
@@ -24,14 +24,14 @@
     private static final long serialVersionUID = 6214790243416807050L;
 
     // setup to use Unsafe.compareAndSwapInt for updates
-    private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static final long valueOffset;
 
     static {
-      try {
-        valueOffset = unsafe.objectFieldOffset
-            (AtomicInteger.class.getDeclaredField("value"));
-      } catch (Exception ex) { throw new Error(ex); }
+        try {
+            valueOffset = unsafe.objectFieldOffset
+                (AtomicInteger.class.getDeclaredField("value"));
+        } catch (Exception ex) { throw new Error(ex); }
     }
 
     private volatile int value;
@@ -217,18 +217,33 @@
     }
 
 
+    /**
+     * Returns the value of this {@code AtomicInteger} as an {@code int}.
+     */
     public int intValue() {
         return get();
     }
 
+    /**
+     * Returns the value of this {@code AtomicInteger} as a {@code long}
+     * after a widening primitive conversion.
+     */
     public long longValue() {
         return (long)get();
     }
 
+    /**
+     * Returns the value of this {@code AtomicInteger} as a {@code float}
+     * after a widening primitive conversion.
+     */
     public float floatValue() {
         return (float)get();
     }
 
+    /**
+     * Returns the value of this {@code AtomicInteger} as a {@code double}
+     * after a widening primitive conversion.
+     */
     public double doubleValue() {
         return (double)get();
     }
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
index 6dcdfd0..804a51e 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
@@ -1,12 +1,11 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
 import sun.misc.Unsafe;
-import java.util.*;
 
 /**
  * An {@code int} array in which elements may be updated atomically.
@@ -19,7 +18,7 @@
 public class AtomicIntegerArray implements java.io.Serializable {
     private static final long serialVersionUID = 2862133569453604235L;
 
-    private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static final int base = unsafe.arrayBaseOffset(int[].class);
     private static final int shift;
     private final int[] array;
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
index e8a0d57..c7ed158 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
@@ -236,24 +236,21 @@
      * Standard hotspot implementation using intrinsics
      */
     private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> {
-        private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+        private static final Unsafe unsafe = Unsafe.getUnsafe();
         private final long offset;
         private final Class<T> tclass;
-        private final Class cclass;
+        private final Class<?> cclass;
 
         AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName) {
             Field field = null;
-            Class caller = null;
+            Class<?> caller = null;
             int modifiers = 0;
             try {
                 field = tclass.getDeclaredField(fieldName);
-                // BEGIN android-changed
-                caller = VMStack.getStackClass2();
-                // END android-changed
+                caller = VMStack.getStackClass2(); // android-changed
                 modifiers = field.getModifiers();
 
                 // BEGIN android-removed
-                // modifiers = field.getModifiers();
                 // sun.reflect.misc.ReflectUtil.ensureMemberAccess(
                 //     caller, tclass, null, modifiers);
                 // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
@@ -262,7 +259,7 @@
                 throw new RuntimeException(ex);
             }
 
-            Class fieldt = field.getType();
+            Class<?> fieldt = field.getType();
             if (fieldt != int.class)
                 throw new IllegalArgumentException("Must be integer type");
 
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java
index 12d6cd1..5e799f7 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLong.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
@@ -24,7 +24,7 @@
     private static final long serialVersionUID = 1927816293512124184L;
 
     // setup to use Unsafe.compareAndSwapLong for updates
-    private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static final long valueOffset;
 
     /**
@@ -42,10 +42,10 @@
     private static native boolean VMSupportsCS8();
 
     static {
-      try {
-        valueOffset = unsafe.objectFieldOffset
-            (AtomicLong.class.getDeclaredField("value"));
-      } catch (Exception ex) { throw new Error(ex); }
+        try {
+            valueOffset = unsafe.objectFieldOffset
+                (AtomicLong.class.getDeclaredField("value"));
+        } catch (Exception ex) { throw new Error(ex); }
     }
 
     private volatile long value;
@@ -231,18 +231,33 @@
     }
 
 
+    /**
+     * Returns the value of this {@code AtomicLong} as an {@code int}
+     * after a narrowing primitive conversion.
+     */
     public int intValue() {
         return (int)get();
     }
 
+    /**
+     * Returns the value of this {@code AtomicLong} as a {@code long}.
+     */
     public long longValue() {
         return get();
     }
 
+    /**
+     * Returns the value of this {@code AtomicLong} as a {@code float}
+     * after a widening primitive conversion.
+     */
     public float floatValue() {
         return (float)get();
     }
 
+    /**
+     * Returns the value of this {@code AtomicLong} as a {@code double}
+     * after a widening primitive conversion.
+     */
     public double doubleValue() {
         return (double)get();
     }
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
index 9e2d25f..22edb3f 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
@@ -1,12 +1,11 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
 import sun.misc.Unsafe;
-import java.util.*;
 
 /**
  * A {@code long} array in which elements may be updated atomically.
@@ -18,7 +17,7 @@
 public class AtomicLongArray implements java.io.Serializable {
     private static final long serialVersionUID = -2308431214976778248L;
 
-    private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static final int base = unsafe.arrayBaseOffset(long[].class);
     private static final int shift;
     private final long[] array;
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index 21ef748..748ae69 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
@@ -235,14 +235,14 @@
     }
 
     private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
-        private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+        private static final Unsafe unsafe = Unsafe.getUnsafe();
         private final long offset;
         private final Class<T> tclass;
-        private final Class cclass;
+        private final Class<?> cclass;
 
         CASUpdater(Class<T> tclass, String fieldName) {
             Field field = null;
-            Class caller = null;
+            Class<?> caller = null;
             int modifiers = 0;
             try {
                 field = tclass.getDeclaredField(fieldName);
@@ -257,7 +257,7 @@
                 throw new RuntimeException(ex);
             }
 
-            Class fieldt = field.getType();
+            Class<?> fieldt = field.getType();
             if (fieldt != long.class)
                 throw new IllegalArgumentException("Must be long type");
 
@@ -320,14 +320,14 @@
 
 
     private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
-        private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+        private static final Unsafe unsafe = Unsafe.getUnsafe();
         private final long offset;
         private final Class<T> tclass;
-        private final Class cclass;
+        private final Class<?> cclass;
 
         LockedUpdater(Class<T> tclass, String fieldName) {
             Field field = null;
-            Class caller = null;
+            Class<?> caller = null;
             int modifiers = 0;
             try {
                 field = tclass.getDeclaredField(fieldName);
@@ -342,7 +342,7 @@
                 throw new RuntimeException(ex);
             }
 
-            Class fieldt = field.getType();
+            Class<?> fieldt = field.getType();
             if (fieldt != long.class)
                 throw new IllegalArgumentException("Must be long type");
 
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
index 63f46d6f..eaf700c 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicMarkableReference.java
@@ -1,13 +1,11 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
 
-import sun.misc.Unsafe;
-
 /**
  * An {@code AtomicMarkableReference} maintains an object reference
  * along with a mark bit, that can be updated atomically.
@@ -163,7 +161,7 @@
 
     // Unsafe mechanics
 
-    private static final sun.misc.Unsafe UNSAFE = UnsafeAccess.THE_ONE; // android-changed
+    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
     private static final long pairOffset =
         objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class);
 
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java
index f041bbd..b21e9b6 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReference.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
@@ -18,14 +18,14 @@
 public class AtomicReference<V>  implements java.io.Serializable {
     private static final long serialVersionUID = -1848883965231344442L;
 
-    private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static final long valueOffset;
 
     static {
-      try {
-        valueOffset = unsafe.objectFieldOffset
-            (AtomicReference.class.getDeclaredField("value"));
-      } catch (Exception ex) { throw new Error(ex); }
+        try {
+            valueOffset = unsafe.objectFieldOffset
+                (AtomicReference.class.getDeclaredField("value"));
+        } catch (Exception ex) { throw new Error(ex); }
     }
 
     private volatile V value;
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
index dbc5886..c47728d 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
@@ -1,12 +1,14 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
+
+import java.util.Arrays;
+import java.lang.reflect.Array;
 import sun.misc.Unsafe;
-import java.util.*;
 
 /**
  * An array of object references in which elements may be updated
@@ -20,13 +22,23 @@
 public class AtomicReferenceArray<E> implements java.io.Serializable {
     private static final long serialVersionUID = -6209656149925076980L;
 
-    private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
-    private static final int base = unsafe.arrayBaseOffset(Object[].class);
+    private static final Unsafe unsafe;
+    private static final int base;
     private static final int shift;
-    private final Object[] array;
+    private static final long arrayFieldOffset;
+    private final Object[] array; // must have exact type Object[]
 
     static {
-        int scale = unsafe.arrayIndexScale(Object[].class);
+        int scale;
+        try {
+            unsafe = Unsafe.getUnsafe();
+            arrayFieldOffset = unsafe.objectFieldOffset
+                (AtomicReferenceArray.class.getDeclaredField("array"));
+            base = unsafe.arrayBaseOffset(Object[].class);
+            scale = unsafe.arrayIndexScale(Object[].class);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
         if ((scale & (scale - 1)) != 0)
             throw new Error("data type scale not a power of two");
         shift = 31 - Integer.numberOfLeadingZeros(scale);
@@ -45,7 +57,7 @@
 
     /**
      * Creates a new AtomicReferenceArray of the given length, with all
-     * elements initially zero.
+     * elements initially null.
      *
      * @param length the length of the array
      */
@@ -62,7 +74,7 @@
      */
     public AtomicReferenceArray(E[] array) {
         // Visibility guaranteed by final field guarantees
-        this.array = array.clone();
+        this.array = Arrays.copyOf(array, array.length, Object[].class);
     }
 
     /**
@@ -121,7 +133,7 @@
     public final E getAndSet(int i, E newValue) {
         long offset = checkedByteOffset(i);
         while (true) {
-            E current = (E) getRaw(offset);
+            E current = getRaw(offset);
             if (compareAndSetRaw(offset, current, newValue))
                 return current;
         }
@@ -167,7 +179,7 @@
      * @return the String representation of the current values of array
      */
     public String toString() {
-           int iMax = array.length - 1;
+        int iMax = array.length - 1;
         if (iMax == -1)
             return "[]";
 
@@ -181,4 +193,20 @@
         }
     }
 
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * @param s the stream
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException,
+        java.io.InvalidObjectException {
+        // Note: This must be changed if any additional fields are defined
+        Object a = s.readFields().get("array", null);
+        if (a == null || !a.getClass().isArray())
+            throw new java.io.InvalidObjectException("Not array type");
+        if (a.getClass() != Object[].class)
+            a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
+        unsafe.putObjectVolatile(this, arrayFieldOffset, a);
+    }
+
 }
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index 8b3da0b..d23d766 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -1,11 +1,11 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
-import dalvik.system.VMStack;
+import dalvik.system.VMStack; // android-added
 import sun.misc.Unsafe;
 import java.lang.reflect.*;
 
@@ -155,7 +155,7 @@
         private final long offset;
         private final Class<T> tclass;
         private final Class<V> vclass;
-        private final Class cclass;
+        private final Class<?> cclass;
 
         /*
          * Internal type checks within all update methods contain
@@ -173,8 +173,8 @@
                                         Class<V> vclass,
                                         String fieldName) {
             Field field = null;
-            Class fieldClass = null;
-            Class caller = null;
+            Class<?> fieldClass = null;
+            Class<?> caller = null;
             int modifiers = 0;
             try {
                 field = tclass.getDeclaredField(fieldName);
diff --git a/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java b/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
index 2e826f2..a0cb492 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/AtomicStampedReference.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.atomic;
@@ -162,7 +162,7 @@
 
     // Unsafe mechanics
 
-    private static final sun.misc.Unsafe UNSAFE = UnsafeAccess.THE_ONE; // android-changed
+    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
     private static final long pairOffset =
         objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
 
diff --git a/luni/src/main/java/java/util/concurrent/atomic/Fences.java b/luni/src/main/java/java/util/concurrent/atomic/Fences.java
new file mode 100644
index 0000000..7ecf45a
--- /dev/null
+++ b/luni/src/main/java/java/util/concurrent/atomic/Fences.java
@@ -0,0 +1,540 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+/**
+ * A set of methods providing fine-grained control over happens-before
+ * and synchronization order relations among reads and/or writes.  The
+ * methods of this class are designed for use in uncommon situations
+ * where declaring variables {@code volatile} or {@code final}, using
+ * instances of atomic classes, using {@code synchronized} blocks or
+ * methods, or using other synchronization facilities are not possible
+ * or do not provide the desired control.
+ *
+ * <p><b>Memory Ordering.</b> There are three methods for controlling
+ * ordering relations among memory accesses (i.e., reads and
+ * writes). Method {@code orderWrites} is typically used to enforce
+ * order between two writes, and {@code orderAccesses} between a write
+ * and a read.  Method {@code orderReads} is used to enforce order
+ * between two reads with respect to other {@code orderWrites} and/or
+ * {@code orderAccesses} invocations.  The formally specified
+ * properties of these methods described below provide
+ * platform-independent guarantees that are honored by all levels of a
+ * platform (compilers, systems, processors).  The use of these
+ * methods may result in the suppression of otherwise valid compiler
+ * transformations and optimizations that could visibly violate the
+ * specified orderings, and may or may not entail the use of
+ * processor-level "memory barrier" instructions.
+ *
+ * <p>Each ordering method accepts a {@code ref} argument, and
+ * controls ordering among accesses with respect to this reference.
+ * Invocations must be placed <em>between</em> accesses performed in
+ * expression evaluations and assignment statements to control the
+ * orderings of prior versus subsequent accesses appearing in program
+ * order. These methods also return their arguments to simplify
+ * correct usage in these contexts.
+ *
+ * <p>Usages of ordering methods almost always take one of the forms
+ * illustrated in the examples below.  These idioms arrange some of
+ * the ordering properties associated with {@code volatile} and
+ * related language-based constructions, but without other
+ * compile-time and runtime benefits that make language-based
+ * constructions far better choices when they are applicable.  Usages
+ * should be restricted to the control of strictly internal
+ * implementation matters inside a class or package, and must either
+ * avoid or document any consequent violations of ordering or safety
+ * properties expected by users of a class employing them.
+ *
+ * <p><b>Reachability.</b> Method {@code reachabilityFence}
+ * establishes an ordering for strong reachability (as defined in the
+ * {@link java.lang.ref} package specification) with respect to
+ * garbage collection.  Method {@code reachabilityFence} differs from
+ * the others in that it controls relations that are otherwise only
+ * implicit in a program -- the reachability conditions triggering
+ * garbage collection.  As illustrated in the sample usages below,
+ * this method is applicable only when reclamation may have visible
+ * effects, which is possible for objects with finalizers (see Section
+ * 12.6 of the Java Language Specification) that are implemented in
+ * ways that rely on ordering control for correctness.
+ *
+ * <p><b>Sample Usages</b>
+ *
+ * <p><b>Safe publication.</b> With care, method {@code orderWrites}
+ * may be used to obtain the memory safety effects of {@code final}
+ * for a field that cannot be declared as {@code final}, because its
+ * primary initialization cannot be performed in a constructor, in
+ * turn because it is used in a framework requiring that all classes
+ * have a no-argument constructor; as in:
+ *
+ *  <pre> {@code
+ * class WidgetHolder {
+ *   private Widget widget;
+ *   public WidgetHolder() {}
+ *   public static WidgetHolder newWidgetHolder(Params params) {
+ *     WidgetHolder h = new WidgetHolder();
+ *     h.widget = new Widget(params);
+ *     return Fences.orderWrites(h);
+ *   }
+ * }}</pre>
+ *
+ * Here, the invocation of {@code orderWrites} ensures that the
+ * effects of the widget assignment are ordered before those of any
+ * (unknown) subsequent stores of {@code h} in other variables that
+ * make {@code h} available for use by other objects.  Initialization
+ * sequences using {@code orderWrites} require more care than those
+ * involving {@code final} fields.  When {@code final} is not used,
+ * compilers cannot help you to ensure that the field is set correctly
+ * across all usages.  You must fully initialize objects
+ * <em>before</em> the {@code orderWrites} invocation that makes
+ * references to them safe to assign to accessible variables. Further,
+ * initialization sequences must not internally "leak" the reference
+ * by using it as an argument to a callback method or adding it to a
+ * static data structure.  If less constrained usages were required,
+ * it may be possible to cope using more extensive sets of fences, or
+ * as a normally better choice, using synchronization (locking).
+ * Conversely, if it were possible to do so, the best option would be
+ * to rewrite class {@code WidgetHolder} to use {@code final}.
+ *
+ * <p>An alternative approach is to place similar mechanics in the
+ * (sole) method that makes such objects available for use by others.
+ * Here is a stripped-down example illustrating the essentials. In
+ * practice, among other changes, you would use access methods instead
+ * of a public field.
+ *
+ *  <pre> {@code
+ * class AnotherWidgetHolder {
+ *   public Widget widget;
+ *   void publish(Widget w) {
+ *     this.widget = Fences.orderWrites(w);
+ *   }
+ *   // ...
+ * }}</pre>
+ *
+ * In this case, the {@code orderWrites} invocation occurs before the
+ * store making the object available. Correctness again relies on
+ * ensuring that there are no leaks prior to invoking this method, and
+ * that it really is the <em>only</em> means of accessing the
+ * published object.  This approach is not often applicable --
+ * normally you would publish objects using a thread-safe collection
+ * that itself guarantees the expected ordering relations. However, it
+ * may come into play in the construction of such classes themselves.
+ *
+ * <p><b>Safely updating fields.</b> Outside of the initialization
+ * idioms illustrated above, Fence methods ordering writes must be
+ * paired with those ordering reads. To illustrate, suppose class
+ * {@code c} contains an accessible variable {@code data} that should
+ * have been declared as {@code volatile} but wasn't:
+ *
+ *  <pre> {@code
+ * class C {
+ *    Object data;  // need volatile access but not volatile
+ *    // ...
+ * }
+ *
+ * class App {
+ *   Object getData(C c) {
+ *      return Fences.orderReads(c).data;
+ *   }
+ *
+ *   void setData(C c) {
+ *      Object newValue = ...;
+ *      c.data = Fences.orderWrites(newValue);
+ *      Fences.orderAccesses(c);
+ *   }
+ *   // ...
+ * }}</pre>
+ *
+ * Method {@code getData} provides an emulation of {@code volatile}
+ * reads of (non-long/double) fields by ensuring that the read of
+ * {@code c} obtained as an argument is ordered before subsequent
+ * reads using this reference, and then performs the read of its
+ * field. Method {@code setData} provides an emulation of volatile
+ * writes, ensuring that all other relevant writes have completed,
+ * then performing the assignment, and then ensuring that the write is
+ * ordered before any other access.  These techniques may apply even
+ * when fields are not directly accessible, in which case calls to
+ * fence methods would surround calls to methods such as {@code
+ * c.getData()}.  However, these techniques cannot be applied to
+ * {@code long} or {@code double} fields because reads and writes of
+ * fields of these types are not guaranteed to be
+ * atomic. Additionally, correctness may require that all accesses of
+ * such data use these kinds of wrapper methods, which you would need
+ * to manually ensure.
+ *
+ * <p>More generally, Fence methods can be used in this way to achieve
+ * the safety properties of {@code volatile}. However their use does
+ * not necessarily guarantee the full sequential consistency
+ * properties specified in the Java Language Specification chapter 17
+ * for programs using {@code volatile}. In particular, emulation using
+ * Fence methods is not guaranteed to maintain the property that
+ * {@code volatile} operations performed by different threads are
+ * observed in the same order by all observer threads.
+ *
+ * <p><b>Acquire/Release management of threadsafe objects</b>. It may
+ * be possible to use weaker conventions for volatile-like variables
+ * when they are used to keep track of objects that fully manage their
+ * own thread-safety and synchronization.  Here, an acquiring read
+ * operation remains the same as a volatile-read, but a releasing
+ * write differs by virtue of not itself ensuring an ordering of its
+ * write with subsequent reads, because the required effects are
+ * already ensured by the referenced objects.
+ * For example:
+ *
+ *  <pre> {@code
+ * class Item {
+ *    synchronized f(); // ALL methods are synchronized
+ *    // ...
+ * }
+ *
+ * class ItemHolder {
+ *   private Item item;
+ *   Item acquireItem() {
+ *      return Fences.orderReads(item);
+ *   }
+ *
+ *   void releaseItem(Item x) {
+ *      item = Fences.orderWrites(x);
+ *   }
+ *
+ *   // ...
+ * }}</pre>
+ *
+ * Because this construction avoids use of {@code orderAccesses},
+ * which is typically more costly than the other fence methods, it may
+ * result in better performance than using {@code volatile} or its
+ * emulation. However, as is the case with most applications of fence
+ * methods, correctness relies on the usage context -- here, the
+ * thread safety of {@code Item}, as well as the lack of need for full
+ * volatile semantics inside this class itself. However, the second
+ * concern means that it can be difficult to extend the {@code
+ * ItemHolder} class in this example to be more useful.
+ *
+ * <p><b>Avoiding premature finalization.</b> Finalization may occur
+ * whenever a Java Virtual Machine detects that no reference to an
+ * object will ever be stored in the heap: A garbage collector may
+ * reclaim an object even if the fields of that object are still in
+ * use, so long as the object has otherwise become unreachable. This
+ * may have surprising and undesirable effects in cases such as the
+ * following example in which the bookkeeping associated with a class
+ * is managed through array indices. Here, method {@code action}
+ * uses a {@code reachabilityFence} to ensure that the Resource
+ * object is not reclaimed before bookkeeping on an associated
+ * ExternalResource has been performed; in particular here, to ensure
+ * that the array slot holding the ExternalResource is not nulled out
+ * in method {@link Object#finalize}, which may otherwise run
+ * concurrently.
+ *
+ *  <pre> {@code
+ * class Resource {
+ *   private static ExternalResource[] externalResourceArray = ...
+ *
+ *   int myIndex;
+ *   Resource(...) {
+ *     myIndex = ...
+ *     externalResourceArray[myIndex] = ...;
+ *     ...
+ *   }
+ *   protected void finalize() {
+ *     externalResourceArray[myIndex] = null;
+ *     ...
+ *   }
+ *   public void action() {
+ *     try {
+ *       // ...
+ *       int i = myIndex;
+ *       Resource.update(externalResourceArray[i]);
+ *     } finally {
+ *       Fences.reachabilityFence(this);
+ *     }
+ *   }
+ *   private static void update(ExternalResource ext) {
+ *     ext.status = ...;
+ *   }
+ * }}</pre>
+ *
+ * Here, the call to {@code reachabilityFence} is nonintuitively
+ * placed <em>after</em> the call to {@code update}, to ensure that
+ * the array slot is not nulled out by {@link Object#finalize} before
+ * the update, even if the call to {@code action} was the last use of
+ * this object. This might be the case if for example a usage in a
+ * user program had the form {@code new Resource().action();} which
+ * retains no other reference to this Resource.  While probably
+ * overkill here, {@code reachabilityFence} is placed in a {@code
+ * finally} block to ensure that it is invoked across all paths in the
+ * method.  In a method with more complex control paths, you might
+ * need further precautions to ensure that {@code reachabilityFence}
+ * is encountered along all of them.
+ *
+ * <p>It is sometimes possible to better encapsulate use of
+ * {@code reachabilityFence}. Continuing the above example, if it
+ * were OK for the call to method update to proceed even if the
+ * finalizer had already executed (nulling out slot), then you could
+ * localize use of {@code reachabilityFence}:
+ *
+ *  <pre> {@code
+ * public void action2() {
+ *   // ...
+ *   Resource.update(getExternalResource());
+ * }
+ * private ExternalResource getExternalResource() {
+ *   ExternalResource ext = externalResourceArray[myIndex];
+ *   Fences.reachabilityFence(this);
+ *   return ext;
+ * }}</pre>
+ *
+ * <p>Method {@code reachabilityFence} is not required in
+ * constructions that themselves ensure reachability. For example,
+ * because objects that are locked cannot in general be reclaimed, it
+ * would suffice if all accesses of the object, in all methods of
+ * class Resource (including {@code finalize}) were enclosed in {@code
+ * synchronized (this)} blocks. (Further, such blocks must not include
+ * infinite loops, or themselves be unreachable, which fall into the
+ * corner case exceptions to the "in general" disclaimer.) However,
+ * method {@code reachabilityFence} remains a better option in cases
+ * where this approach is not as efficient, desirable, or possible;
+ * for example because it would encounter deadlock.
+ *
+ * <p><b>Formal Properties.</b>
+ *
+ * <p>Using the terminology of The Java Language Specification chapter
+ * 17, the rules governing the semantics of the methods of this class
+ * are as follows:
+ *
+ * <p> The following is still under construction.
+ *
+ * <dl>
+ *
+ *   <dt><b>[Definitions]</b>
+ *   <dd>
+ *   <ul>
+ *
+ *     <li>Define <em>sequenced(a, b)</em> to be true if <em>a</em>
+ *     occurs before <em>b</em> in <em>program order</em>.
+ *
+ *     <li>Define <em>accesses(a, p)</em> to be true if
+ *     <em>a</em> is a read or write of a field (or if an array, an
+ *     element) of the object referenced by <em>p</em>.
+ *
+ *     <li>Define <em>deeplyAccesses(a, p)</em> to be true if either
+ *     <em>accesses(a, p)</em> or <em>deeplyAccesses(a, q)</em> where
+ *     <em>q</em> is the value seen by some read <em>r</em>
+ *     such that <em>accesses(r, p)</em>.
+ *
+ *   </ul>
+ *   <p>
+ *   <dt><b>[Matching]</b>
+ *   <dd> Given:
+ *
+ *   <ul>
+ *
+ *     <li><em>p</em>, a reference to an object
+ *
+ *     <li><em>wf</em>, an invocation of {@code orderWrites(p)} or
+ *       {@code orderAccesses(p)}
+ *
+ *     <li><em>w</em>, a write of value <em>p</em>
+ *
+ *     <li> <em>rf</em>, an invocation of {@code orderReads(p)} or
+ *     {@code orderAccesses(p)}
+ *
+ *     <li> <em>r</em>, a read returning value <em>p</em>
+ *
+ *   </ul>
+ *   If:
+ *   <ul>
+ *     <li>sequenced(wf, w)
+ *     <li>read <em>r</em> sees write <em>w</em>
+ *     <li>sequenced(r, rf)
+ *   </ul>
+ *   Then:
+ *   <ul>
+ *
+ *     <li> <em>wf happens-before rf</em>
+ *
+ *     <li> <em>wf</em> precedes <em>rf</em> in the
+ *          <em>synchronization order</em>
+ *
+ *     <li> If (<em>r1</em>, <em>w1</em>) and (<em>r2</em>,
+ *     <em>w2</em>) are two pairs of reads and writes, both
+ *     respectively satisfying the above conditions for <em>p</em>,
+ *     and sequenced(r1, r2) then it is not the case that <em>w2
+ *     happens-before w1</em>.
+ *
+ *   </ul>
+ *   <p>
+ *   <dt><b>[Initial Reads]</b>
+ *   <dd> Given:
+ *
+ *   <ul>
+ *
+ *     <li><em>p</em>, a reference to an object
+ *
+ *     <li> <em>a</em>, an access where deeplyAccesses(a, p)
+ *
+ *     <li><em>wf</em>, an invocation of {@code orderWrites(p)} or
+ *       {@code orderAccesses(p)}
+ *
+ *     <li><em>w</em>, a write of value <em>p</em>
+ *
+ *     <li> <em>r</em>, a read returning value <em>p</em>
+ *
+ *     <li> <em>b</em>, an access where accesses(b, p)
+ *
+ *   </ul>
+ *   If:
+ *   <ul>
+ *     <li>sequenced(a, wf);
+ *     <li>sequenced(wf, w)
+ *     <li>read <em>r</em> sees write <em>w</em>, and
+ *         <em>r</em> is the first read by some thread
+ *         <em>t</em> that sees value <em>p</em>
+ *     <li>sequenced(r, b)
+ *   </ul>
+ *   Then:
+ *   <ul>
+ *     <li> the effects of <em>b</em> are constrained
+ *          by the relation <em>a happens-before b</em>.
+ *   </ul>
+ *  <p>
+ *  <dt><b>[orderAccesses]</b>
+ *  <dd> Given:
+ *
+ *   <ul>
+ *     <li><em>p</em>, a reference to an object
+ *     <li><em>f</em>, an invocation of {@code orderAccesses(p)}
+ *   </ul>
+ *   If:
+ *   <ul>
+ *     <li>sequenced(f, w)
+ *   </ul>
+ *
+ *    Then:
+ *
+ *   <ul>
+ *
+ *     <li> <em>f</em> is an element of the <em>synchronization order</em>.
+ *
+ *   </ul>
+ *   <p>
+ *   <dt><b>[Reachability]</b>
+ *   <dd> Given:
+ *
+ *   <ul>
+ *
+ *     <li><em>p</em>, a reference to an object
+ *
+ *     <li><em>f</em>, an invocation of {@code reachabilityFence(p)}
+ *
+ *     <li><em>a</em>, an access where accesses(a, p)
+ *
+ *     <li><em>b</em>, an action (by a garbage collector) taking
+ *     the form of an invocation of {@code
+ *     p.finalize()} or of enqueing any {@link
+ *     java.lang.ref.Reference} constructed with argument <em>p</em>
+ *
+ *   </ul>
+ *
+ *   If:
+ *   <ul>
+ *     <li>sequenced(a, f)
+ *   </ul>
+ *
+ *    Then:
+ *
+ *   <ul>
+ *
+ *     <li> <em>a happens-before b</em>.
+ *
+ *   </ul>
+ *
+ * </dl>
+ *
+ * @since 1.7
+ * @hide
+ * @author Doug Lea
+ */
+public class Fences {
+    private Fences() {} // Non-instantiable
+
+    /*
+     * The methods of this class are intended to be intrinisified by a
+     * JVM. However, we provide correct but inefficient Java-level
+     * code that simply reads and writes a static volatile
+     * variable. Without JVM support, the consistency effects are
+     * stronger than necessary, and the memory contention effects can
+     * be a serious performance issue.
+     */
+    private static volatile int theVolatile;
+
+    /**
+     * Informally: Ensures that a read of the given reference prior to
+     * the invocation of this method occurs before a subsequent use of
+     * the given reference with the effect of reading or writing a
+     * field (or if an array, element) of the referenced object.  The
+     * use of this method is sensible only when paired with other
+     * invocations of {@link #orderWrites} and/or {@link
+     * #orderAccesses} for the given reference. For details, see the
+     * class documentation for this class.
+     *
+     * @param ref the reference. If null, this method has no effect.
+     * @return the given ref, to simplify usage
+     */
+    public static <T> T orderReads(T ref) {
+        int ignore = theVolatile;
+        return ref;
+    }
+
+    /**
+     * Informally: Ensures that a use of the given reference with the
+     * effect of reading or writing a field (or if an array, element)
+     * of the referenced object, prior to the invocation of this
+     * method occur before a subsequent write of the reference. For
+     * details, see the class documentation for this class.
+     *
+     * @param ref the reference. If null, this method has no effect.
+     * @return the given ref, to simplify usage
+     */
+    public static <T> T orderWrites(T ref) {
+        theVolatile = 0;
+        return ref;
+    }
+
+    /**
+     * Informally: Ensures that accesses (reads or writes) using the
+     * given reference prior to the invocation of this method occur
+     * before subsequent accesses.  For details, see the class
+     * documentation for this class.
+     *
+     * @param ref the reference. If null, this method has no effect.
+     * @return the given ref, to simplify usage
+     */
+    public static <T> T orderAccesses(T ref) {
+        theVolatile = 0;
+        return ref;
+    }
+
+    /**
+     * Ensures that the object referenced by the given reference
+     * remains <em>strongly reachable</em> (as defined in the {@link
+     * java.lang.ref} package documentation), regardless of any prior
+     * actions of the program that might otherwise cause the object to
+     * become unreachable; thus, the referenced object is not
+     * reclaimable by garbage collection at least until after the
+     * invocation of this method. Invocation of this method does not
+     * itself initiate garbage collection or finalization.
+     *
+     * <p>See the class-level documentation for further explanation
+     * and usage examples.
+     *
+     * @param ref the reference. If null, this method has no effect.
+     */
+    public static void reachabilityFence(Object ref) {
+        if (ref != null) {
+            synchronized (ref) {}
+        }
+    }
+}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/UnsafeAccess.java b/luni/src/main/java/java/util/concurrent/atomic/UnsafeAccess.java
deleted file mode 100644
index 96fff17..0000000
--- a/luni/src/main/java/java/util/concurrent/atomic/UnsafeAccess.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.util.concurrent.atomic;
-
-import sun.misc.Unsafe;
-
-/**
- * Easy access to {@link Unsafe} for the rest of this package.
- */
-/*package*/ final class UnsafeAccess {
-    /** non-null; unique instance of {@link Unsafe} */
-    /*package*/ static final Unsafe THE_ONE = Unsafe.getUnsafe();
-
-    /**
-     * This class is uninstantiable.
-     */
-    private UnsafeAccess() {
-        // This space intentionally left blank.
-    }
-}
diff --git a/luni/src/main/java/java/util/concurrent/atomic/package-info.java b/luni/src/main/java/java/util/concurrent/atomic/package-info.java
index 4a4375d..efbb413 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/package-info.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/package-info.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 /**
@@ -11,9 +11,7 @@
  * array elements to those that also provide an atomic conditional update
  * operation of the form:
  *
- * <pre>
- *   boolean compareAndSet(expectedValue, updateValue);
- * </pre>
+ *  <pre> {@code boolean compareAndSet(expectedValue, updateValue);}</pre>
  *
  * <p>This method (which varies in argument types across different
  * classes) atomically sets a variable to the {@code updateValue} if it
@@ -40,15 +38,30 @@
  * {@code AtomicInteger} provide atomic increment methods.  One
  * application is to generate sequence numbers, as in:
  *
- * <pre>
+ *  <pre> {@code
  * class Sequencer {
  *   private final AtomicLong sequenceNumber
  *     = new AtomicLong(0);
  *   public long next() {
  *     return sequenceNumber.getAndIncrement();
  *   }
- * }
- * </pre>
+ * }}</pre>
+ *
+ * <p>It is straightforward to define new utility functions that, like
+ * {@code getAndIncrement}, apply a function to a value atomically.
+ * For example, given some transformation
+ * <pre> {@code long transform(long input)}</pre>
+ *
+ * write your utility method as follows:
+ *  <pre> {@code
+ * boolean getAndTransform(AtomicLong var) {
+ *   while (true) {
+ *     long current = var.get();
+ *     long next = transform(current);
+ *     if (var.compareAndSet(current, next))
+ *         return current;
+ *   }
+ * }}</pre>
  *
  * <p>The memory effects for accesses and updates of atomics generally
  * follow the rules for volatiles, as stated in
@@ -161,9 +174,9 @@
  * {@code byte} values, and cast appropriately.
  *
  * You can also hold floats using
- * {@link java.lang.Float#floatToIntBits} and
+ * {@link java.lang.Float#floatToRawIntBits} and
  * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
- * {@link java.lang.Double#doubleToLongBits} and
+ * {@link java.lang.Double#doubleToRawLongBits} and
  * {@link java.lang.Double#longBitsToDouble} conversions.
  *
  * @since 1.5
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
index f3780e5..4bec0cf 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.locks;
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
index 5c8111c..7b36460 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -1,13 +1,12 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.locks;
 import java.util.*;
 import java.util.concurrent.*;
-import java.util.concurrent.atomic.*;
 import sun.misc.Unsafe;
 
 /**
@@ -569,7 +568,7 @@
     /**
      * Convenience method to interrupt current thread.
      */
-    private static void selfInterrupt() {
+    static void selfInterrupt() {
         Thread.currentThread().interrupt();
     }
 
@@ -1231,7 +1230,7 @@
      * due to the queue being empty.
      *
      * <p>This method is designed to be used by a fair synchronizer to
-     * avoid <a href="AbstractQueuedSynchronizer#barging">barging</a>.
+     * avoid <a href="AbstractQueuedSynchronizer.html#barging">barging</a>.
      * Such a synchronizer's {@link #tryAcquire} method should return
      * {@code false}, and its {@link #tryAcquireShared} method should
      * return a negative value, if this method returns {@code true}
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index 065f130..42029f0 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -1,13 +1,12 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.locks;
 import java.util.*;
 import java.util.concurrent.*;
-import java.util.concurrent.atomic.*;
 import sun.misc.Unsafe;
 
 // BEGIN android-note
@@ -173,7 +172,7 @@
  * It also supports conditions and exposes
  * one of the instrumentation methods:
  *
- * <pre>
+ *  <pre> {@code
  * class Mutex implements Lock, java.io.Serializable {
  *
  *   // Our internal helper class
@@ -229,15 +228,14 @@
  *       throws InterruptedException {
  *     return sync.tryAcquireNanos(1, unit.toNanos(timeout));
  *   }
- * }
- * </pre>
+ * }}</pre>
  *
  * <p>Here is a latch class that is like a {@link CountDownLatch}
  * except that it only requires a single <tt>signal</tt> to
  * fire. Because a latch is non-exclusive, it uses the <tt>shared</tt>
  * acquire and release methods.
  *
- * <pre>
+ *  <pre> {@code
  * class BooleanLatch {
  *
  *   private static class Sync extends AbstractQueuedSynchronizer {
@@ -259,8 +257,7 @@
  *   public void await() throws InterruptedException {
  *     sync.acquireSharedInterruptibly(1);
  *   }
- * }
- * </pre>
+ * }}</pre>
  *
  * @since 1.5
  * @author Doug Lea
@@ -800,7 +797,7 @@
     /**
      * Convenience method to interrupt current thread.
      */
-    private static void selfInterrupt() {
+    static void selfInterrupt() {
         Thread.currentThread().interrupt();
     }
 
@@ -2251,9 +2248,7 @@
      * are at it, we do the same for other CASable fields (which could
      * otherwise be done with atomic field updaters).
      */
-    // BEGIN android-changed
-    private static final Unsafe unsafe = UnsafeAccess.THE_ONE;
-    // END android-changed
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static final long stateOffset;
     private static final long headOffset;
     private static final long tailOffset;
diff --git a/luni/src/main/java/java/util/concurrent/locks/Condition.java b/luni/src/main/java/java/util/concurrent/locks/Condition.java
index 8504e1f..7050df9 100644
--- a/luni/src/main/java/java/util/concurrent/locks/Condition.java
+++ b/luni/src/main/java/java/util/concurrent/locks/Condition.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.locks;
@@ -331,10 +331,9 @@
     /**
      * Causes the current thread to wait until it is signalled or interrupted,
      * or the specified waiting time elapses. This method is behaviorally
-     * equivalent to:<br>
-     * <pre>
-     *   awaitNanos(unit.toNanos(time)) &gt; 0
-     * </pre>
+     * equivalent to:
+     *  <pre> {@code awaitNanos(unit.toNanos(time)) > 0}</pre>
+     *
      * @param time the maximum time to wait
      * @param unit the time unit of the {@code time} argument
      * @return {@code false} if the waiting time detectably elapsed
diff --git a/luni/src/main/java/java/util/concurrent/locks/Lock.java b/luni/src/main/java/java/util/concurrent/locks/Lock.java
index 4b9abd6..d5c6294 100644
--- a/luni/src/main/java/java/util/concurrent/locks/Lock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/Lock.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.locks;
@@ -48,14 +48,14 @@
  * methods and statements. In most cases, the following idiom
  * should be used:
  *
- * <pre><tt>     Lock l = ...;
- *     l.lock();
- *     try {
- *         // access the resource protected by this lock
- *     } finally {
- *         l.unlock();
- *     }
- * </tt></pre>
+ *  <pre> {@code
+ * Lock l = ...;
+ * l.lock();
+ * try {
+ *   // access the resource protected by this lock
+ * } finally {
+ *   l.unlock();
+ * }}</pre>
  *
  * When locking and unlocking occur in different scopes, care must be
  * taken to ensure that all code that is executed while the lock is
@@ -210,18 +210,18 @@
      * immediately with the value {@code false}.
      *
      * <p>A typical usage idiom for this method would be:
-     * <pre>
-     *      Lock lock = ...;
-     *      if (lock.tryLock()) {
-     *          try {
-     *              // manipulate protected state
-     *          } finally {
-     *              lock.unlock();
-     *          }
-     *      } else {
-     *          // perform alternative actions
-     *      }
-     * </pre>
+     *  <pre> {@code
+     * Lock lock = ...;
+     * if (lock.tryLock()) {
+     *   try {
+     *     // manipulate protected state
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * } else {
+     *   // perform alternative actions
+     * }}</pre>
+     *
      * This usage ensures that the lock is unlocked if it was acquired, and
      * doesn't try to unlock if the lock was not acquired.
      *
diff --git a/luni/src/main/java/java/util/concurrent/locks/LockSupport.java b/luni/src/main/java/java/util/concurrent/locks/LockSupport.java
index 0c0f07d..422e428 100644
--- a/luni/src/main/java/java/util/concurrent/locks/LockSupport.java
+++ b/luni/src/main/java/java/util/concurrent/locks/LockSupport.java
@@ -1,11 +1,10 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.locks;
-import java.util.concurrent.*;
 import sun.misc.Unsafe;
 
 
@@ -49,7 +48,10 @@
  * higher-level synchronization utilities, and are not in themselves
  * useful for most concurrency control applications.  The {@code park}
  * method is designed for use only in constructions of the form:
- * <pre>while (!canProceed()) { ... LockSupport.park(this); }</pre>
+ *
+ *  <pre> {@code
+ * while (!canProceed()) { ... LockSupport.park(this); }}</pre>
+ *
  * where neither {@code canProceed} nor any other actions prior to the
  * call to {@code park} entail locking or blocking.  Because only one
  * permit is associated with each thread, any intermediary uses of
@@ -57,7 +59,7 @@
  *
  * <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out
  * non-reentrant lock class:
- * <pre>{@code
+ *  <pre> {@code
  * class FIFOMutex {
  *   private final AtomicBoolean locked = new AtomicBoolean(false);
  *   private final Queue<Thread> waiters
@@ -92,7 +94,7 @@
     private LockSupport() {} // Cannot be instantiated.
 
     // Hotspot implementation via intrinsics API
-    private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
     private static final long parkBlockerOffset;
 
     static {
@@ -246,10 +248,14 @@
      * snapshot -- the thread may have since unblocked or blocked on a
      * different blocker object.
      *
+     * @param t the thread
      * @return the blocker
+     * @throws NullPointerException if argument is null
      * @since 1.6
      */
     public static Object getBlocker(Thread t) {
+        if (t == null)
+            throw new NullPointerException();
         return unsafe.getObjectVolatile(t, parkBlockerOffset);
     }
 
diff --git a/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java b/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java
index 484f68d..bb7b388 100644
--- a/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/ReadWriteLock.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.locks;
diff --git a/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java b/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
index cf787ca..07baf41 100644
--- a/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/ReentrantLock.java
@@ -1,13 +1,12 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.locks;
 import java.util.*;
 import java.util.concurrent.*;
-import java.util.concurrent.atomic.*;
 
 /**
  * A reentrant mutual exclusion {@link Lock} with the same basic
@@ -44,7 +43,7 @@
  * follow a call to {@code lock} with a {@code try} block, most
  * typically in a before/after construction such as:
  *
- * <pre>
+ *  <pre> {@code
  * class X {
  *   private final ReentrantLock lock = new ReentrantLock();
  *   // ...
@@ -57,8 +56,7 @@
  *       lock.unlock()
  *     }
  *   }
- * }
- * </pre>
+ * }}</pre>
  *
  * <p>In addition to implementing the {@link Lock} interface, this
  * class defines methods {@code isLocked} and
@@ -354,8 +352,11 @@
      * method. If you want a timed {@code tryLock} that does permit barging on
      * a fair lock then combine the timed and un-timed forms together:
      *
-     * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
-     * </pre>
+     *  <pre> {@code
+     * if (lock.tryLock() ||
+     *     lock.tryLock(timeout, unit)) {
+     *   ...
+     * }}</pre>
      *
      * <p>If the current thread
      * already holds this lock then the hold count is incremented by one and
@@ -485,7 +486,7 @@
      * not be entered with the lock already held then we can assert that
      * fact:
      *
-     * <pre>
+     *  <pre> {@code
      * class X {
      *   ReentrantLock lock = new ReentrantLock();
      *   // ...
@@ -498,8 +499,7 @@
      *       lock.unlock();
      *     }
      *   }
-     * }
-     * </pre>
+     * }}</pre>
      *
      * @return the number of holds on this lock by the current thread,
      *         or zero if this lock is not held by the current thread
@@ -516,7 +516,7 @@
      * testing. For example, a method that should only be called while
      * a lock is held can assert that this is the case:
      *
-     * <pre>
+     *  <pre> {@code
      * class X {
      *   ReentrantLock lock = new ReentrantLock();
      *   // ...
@@ -525,13 +525,12 @@
      *       assert lock.isHeldByCurrentThread();
      *       // ... method body
      *   }
-     * }
-     * </pre>
+     * }}</pre>
      *
      * <p>It can also be used to ensure that a reentrant lock is used
      * in a non-reentrant manner, for example:
      *
-     * <pre>
+     *  <pre> {@code
      * class X {
      *   ReentrantLock lock = new ReentrantLock();
      *   // ...
@@ -545,8 +544,7 @@
      *           lock.unlock();
      *       }
      *   }
-     * }
-     * </pre>
+     * }}</pre>
      *
      * @return {@code true} if current thread holds this lock and
      *         {@code false} otherwise
diff --git a/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java b/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
index b1a1a60..244a4a7 100644
--- a/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
+++ b/luni/src/main/java/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -1,12 +1,11 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 package java.util.concurrent.locks;
 import java.util.concurrent.*;
-import java.util.concurrent.atomic.*;
 import java.util.*;
 
 /**
@@ -33,7 +32,7 @@
  * <dt><b><i>Fair mode</i></b>
  * <dd> When constructed as fair, threads contend for entry using an
  * approximately arrival-order policy. When the currently held lock
- * is released either the longest-waiting single writer thread will
+ * is released, either the longest-waiting single writer thread will
  * be assigned the write lock, or if there is a group of reader threads
  * waiting longer than all waiting writer threads, that group will be
  * assigned the read lock.
@@ -51,8 +50,8 @@
  * will block unless both the read lock and write lock are free (which
  * implies there are no waiting threads).  (Note that the non-blocking
  * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods
- * do not honor this fair setting and will acquire the lock if it is
- * possible, regardless of waiting threads.)
+ * do not honor this fair setting and will immediately acquire the lock
+ * if it is possible, regardless of waiting threads.)
  * <p>
  * </dl>
  *
@@ -114,21 +113,21 @@
  *   void processCachedData() {
  *     rwl.readLock().lock();
  *     if (!cacheValid) {
- *        // Must release read lock before acquiring write lock
- *        rwl.readLock().unlock();
- *        rwl.writeLock().lock();
- *        try {
- *          // Recheck state because another thread might have
- *          // acquired write lock and changed state before we did.
- *          if (!cacheValid) {
- *            data = ...
- *            cacheValid = true;
- *          }
- *          // Downgrade by acquiring read lock before releasing write lock
- *          rwl.readLock().lock();
- *        } finally {
- *          rwl.writeLock().unlock(); // Unlock write, still hold read
- *        }
+ *       // Must release read lock before acquiring write lock
+ *       rwl.readLock().unlock();
+ *       rwl.writeLock().lock();
+ *       try {
+ *         // Recheck state because another thread might have
+ *         // acquired write lock and changed state before we did.
+ *         if (!cacheValid) {
+ *           data = ...
+ *           cacheValid = true;
+ *         }
+ *         // Downgrade by acquiring read lock before releasing write lock
+ *         rwl.readLock().lock();
+ *       } finally {
+ *         rwl.writeLock().unlock(); // Unlock write, still hold read
+ *       }
  *     }
  *
  *     try {
@@ -147,33 +146,33 @@
  * is a class using a TreeMap that is expected to be large and
  * concurrently accessed.
  *
- * <pre>{@code
+ *  <pre> {@code
  * class RWDictionary {
- *    private final Map<String, Data> m = new TreeMap<String, Data>();
- *    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
- *    private final Lock r = rwl.readLock();
- *    private final Lock w = rwl.writeLock();
+ *   private final Map<String, Data> m = new TreeMap<String, Data>();
+ *   private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ *   private final Lock r = rwl.readLock();
+ *   private final Lock w = rwl.writeLock();
  *
- *    public Data get(String key) {
- *        r.lock();
- *        try { return m.get(key); }
- *        finally { r.unlock(); }
- *    }
- *    public String[] allKeys() {
- *        r.lock();
- *        try { return m.keySet().toArray(); }
- *        finally { r.unlock(); }
- *    }
- *    public Data put(String key, Data value) {
- *        w.lock();
- *        try { return m.put(key, value); }
- *        finally { w.unlock(); }
- *    }
- *    public void clear() {
- *        w.lock();
- *        try { m.clear(); }
- *        finally { w.unlock(); }
- *    }
+ *   public Data get(String key) {
+ *     r.lock();
+ *     try { return m.get(key); }
+ *     finally { r.unlock(); }
+ *   }
+ *   public String[] allKeys() {
+ *     r.lock();
+ *     try { return m.keySet().toArray(); }
+ *     finally { r.unlock(); }
+ *   }
+ *   public Data put(String key, Data value) {
+ *     w.lock();
+ *     try { return m.put(key, value); }
+ *     finally { w.unlock(); }
+ *   }
+ *   public void clear() {
+ *     w.lock();
+ *     try { m.clear(); }
+ *     finally { w.unlock(); }
+ *   }
  * }}</pre>
  *
  * <h3>Implementation Notes</h3>
@@ -625,7 +624,9 @@
         }
 
         /**
-         * Reconstitute this lock instance from a stream
+         * Reconstitutes this lock instance from a stream (that is,
+         * deserializes it).
+         *
          * @param s the stream
          */
         private void readObject(java.io.ObjectInputStream s)
@@ -790,8 +791,11 @@
          * permit barging on a fair lock then combine the timed and
          * un-timed forms together:
          *
-         * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
-         * </pre>
+         *  <pre> {@code
+         * if (lock.tryLock() ||
+         *     lock.tryLock(timeout, unit)) {
+         *   ...
+         * }}</pre>
          *
          * <p>If the write lock is held by another thread then the
          * current thread becomes disabled for thread scheduling
@@ -1020,8 +1024,11 @@
          * that does permit barging on a fair lock then combine the
          * timed and un-timed forms together:
          *
-         * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
-         * </pre>
+         *  <pre> {@code
+         * if (lock.tryLock() ||
+         *     lock.tryLock(timeout, unit)) {
+         *   ...
+         * }}</pre>
          *
          * <p>If the current thread already holds this lock then the
          * hold count is incremented by one and the method returns
diff --git a/luni/src/main/java/java/util/concurrent/locks/UnsafeAccess.java b/luni/src/main/java/java/util/concurrent/locks/UnsafeAccess.java
deleted file mode 100644
index 07f64e4..0000000
--- a/luni/src/main/java/java/util/concurrent/locks/UnsafeAccess.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.util.concurrent.locks;
-
-import sun.misc.Unsafe;
-
-/**
- * Easy access to {@link Unsafe} for the rest of this package.
- */
-/*package*/ final class UnsafeAccess {
-    /** non-null; unique instance of {@link Unsafe} */
-    /*package*/ static final Unsafe THE_ONE = Unsafe.getUnsafe();
-
-    /**
-     * This class is uninstantiable.
-     */
-    private UnsafeAccess() {
-        // This space intentionally left blank.
-    }
-}
diff --git a/luni/src/main/java/java/util/concurrent/locks/package-info.java b/luni/src/main/java/java/util/concurrent/locks/package-info.java
index 860acdd..433f869 100644
--- a/luni/src/main/java/java/util/concurrent/locks/package-info.java
+++ b/luni/src/main/java/java/util/concurrent/locks/package-info.java
@@ -1,7 +1,7 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 /**
diff --git a/luni/src/main/java/java/util/concurrent/package-info.java b/luni/src/main/java/java/util/concurrent/package-info.java
index 8509a41..155d1b8 100644
--- a/luni/src/main/java/java/util/concurrent/package-info.java
+++ b/luni/src/main/java/java/util/concurrent/package-info.java
@@ -1,11 +1,11 @@
 /*
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // BEGIN android-note
-// Dropped references to unreleased APIs (ForkJoinPool, Phaser, etc.)
+// omit links to ForkJoinPool, ForkJoinTask, LinkedTransferQueue, PHaser, TransferQueue
 // END android-note
 
 /**
@@ -111,7 +111,7 @@
  *
  * <h2>Synchronizers</h2>
  *
- * Five classes aid common special-purpose synchronization idioms.
+ * Four classes aid common special-purpose synchronization idioms.
  * <ul>
  *
  * <li>{@link java.util.concurrent.Semaphore} is a classic concurrency tool.
@@ -146,7 +146,7 @@
  * A {@code CopyOnWriteArrayList} is preferable to a synchronized
  * {@code ArrayList} when the expected number of reads and traversals
  * greatly outnumber the number of updates to a list.
-
+ *
  * <p>The "Concurrent" prefix used with some classes in this package
  * is a shorthand indicating several differences from similar
  * "synchronized" classes.  For example {@code java.util.Hashtable} and
@@ -243,7 +243,8 @@
  *   in each thread <i>happen-before</i> those subsequent to the
  *   corresponding {@code exchange()} in another thread.
  *
- *   <li>Actions prior to calling {@code CyclicBarrier.await}
+ *   <li>Actions prior to calling {@code CyclicBarrier.await} and
+ *   {@code Phaser.awaitAdvance} (as well as its variants)
  *   <i>happen-before</i> actions performed by the barrier action, and
  *   actions performed by the barrier action <i>happen-before</i> actions
  *   subsequent to a successful return from the corresponding {@code await}
diff --git a/luni/src/main/java/java/util/jar/JarOutputStream.java b/luni/src/main/java/java/util/jar/JarOutputStream.java
index 78e3aa5..fc0645e 100644
--- a/luni/src/main/java/java/util/jar/JarOutputStream.java
+++ b/luni/src/main/java/java/util/jar/JarOutputStream.java
@@ -37,20 +37,20 @@
      *
      * @param os
      *            the {@code OutputStream} to write to
-     * @param mf
+     * @param manifest
      *            the {@code Manifest} to output for this JAR file.
      * @throws IOException
      *             if an error occurs creating the {@code JarOutputStream}.
      */
-    public JarOutputStream(OutputStream os, Manifest mf) throws IOException {
+    public JarOutputStream(OutputStream os, Manifest manifest) throws IOException {
         super(os);
-        if (mf == null) {
-            throw new NullPointerException();
+        if (manifest == null) {
+            throw new NullPointerException("manifest == null");
         }
-        manifest = mf;
+        this.manifest = manifest;
         ZipEntry ze = new ZipEntry(JarFile.MANIFEST_NAME);
         putNextEntry(ze);
-        manifest.write(this);
+        this.manifest.write(this);
         closeEntry();
     }
 
diff --git a/luni/src/main/java/java/util/logging/FileHandler.java b/luni/src/main/java/java/util/logging/FileHandler.java
index 980955a..6ffef87 100644
--- a/luni/src/main/java/java/util/logging/FileHandler.java
+++ b/luni/src/main/java/java/util/logging/FileHandler.java
@@ -214,8 +214,10 @@
         String className = this.getClass().getName();
         pattern = (p == null) ? getStringProperty(className + ".pattern",
                 DEFAULT_PATTERN) : p;
-        if (pattern == null || pattern.isEmpty()) {
-            throw new NullPointerException("Pattern cannot be empty or null");
+        if (pattern == null) {
+            throw new NullPointerException("pattern == null");
+        } else if (pattern.isEmpty()) {
+            throw new NullPointerException("pattern.isEmpty()");
         }
         append = (a == null) ? getBooleanProperty(className + ".append",
                 DEFAULT_APPEND) : a.booleanValue();
diff --git a/luni/src/main/java/java/util/logging/Handler.java b/luni/src/main/java/java/util/logging/Handler.java
index 5a6c14e..13dbdd5 100644
--- a/luni/src/main/java/java/util/logging/Handler.java
+++ b/luni/src/main/java/java/util/logging/Handler.java
@@ -227,7 +227,7 @@
      */
     public boolean isLoggable(LogRecord record) {
         if (record == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("record == null");
         }
         if (this.level.intValue() == Level.OFF.intValue()) {
             return false;
@@ -294,17 +294,17 @@
     /**
      * Sets the error manager for this handler.
      *
-     * @param em
+     * @param newErrorManager
      *            the error manager to set.
      * @throws NullPointerException
      *             if {@code em} is {@code null}.
      */
-    public void setErrorManager(ErrorManager em) {
+    public void setErrorManager(ErrorManager newErrorManager) {
         LogManager.getLogManager().checkAccess();
-        if (em == null) {
-            throw new NullPointerException();
+        if (newErrorManager == null) {
+            throw new NullPointerException("newErrorManager == null");
         }
-        this.errorMan = em;
+        this.errorMan = newErrorManager;
     }
 
     /**
@@ -327,7 +327,7 @@
      */
     void internalSetFormatter(Formatter newFormatter) {
         if (newFormatter == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("newFormatter == null");
         }
         this.formatter = newFormatter;
     }
@@ -356,7 +356,7 @@
      */
     public void setLevel(Level newLevel) {
         if (newLevel == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("newLevel == null");
         }
         LogManager.getLogManager().checkAccess();
         this.level = newLevel;
diff --git a/luni/src/main/java/java/util/logging/LogManager.java b/luni/src/main/java/java/util/logging/LogManager.java
index 449c263..8877cd5 100644
--- a/luni/src/main/java/java/util/logging/LogManager.java
+++ b/luni/src/main/java/java/util/logging/LogManager.java
@@ -446,7 +446,7 @@
      */
     public void addPropertyChangeListener(PropertyChangeListener l) {
         if (l == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("l == null");
         }
         checkAccess();
         listeners.addPropertyChangeListener(l);
diff --git a/luni/src/main/java/java/util/logging/StreamHandler.java b/luni/src/main/java/java/util/logging/StreamHandler.java
index 7581835..60b4321 100644
--- a/luni/src/main/java/java/util/logging/StreamHandler.java
+++ b/luni/src/main/java/java/util/logging/StreamHandler.java
@@ -167,7 +167,7 @@
      */
     protected void setOutputStream(OutputStream os) {
         if (os == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("os == null");
         }
         LogManager.getLogManager().checkAccess();
         close(true);
diff --git a/luni/src/main/java/java/util/prefs/AbstractPreferences.java b/luni/src/main/java/java/util/prefs/AbstractPreferences.java
index d86d789..71110c3 100644
--- a/luni/src/main/java/java/util/prefs/AbstractPreferences.java
+++ b/luni/src/main/java/java/util/prefs/AbstractPreferences.java
@@ -372,7 +372,7 @@
     @Override
     public void exportNode(OutputStream ostream) throws IOException, BackingStoreException {
         if (ostream == null) {
-            throw new NullPointerException("Stream is null");
+            throw new NullPointerException("ostream == null");
         }
         checkState();
         XMLParser.exportPrefs(this, ostream, false);
@@ -381,7 +381,7 @@
     @Override
     public void exportSubtree(OutputStream ostream) throws IOException, BackingStoreException {
         if (ostream == null) {
-            throw new NullPointerException("Stream is null");
+            throw new NullPointerException("ostream == null");
         }
         checkState();
         XMLParser.exportPrefs(this, ostream, true);
@@ -402,7 +402,7 @@
     @Override
     public String get(String key, String deflt) {
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
         String result = null;
         synchronized (lock) {
@@ -597,7 +597,7 @@
     @Override
     public boolean nodeExists(String name) throws BackingStoreException {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
         AbstractPreferences startNode = null;
         synchronized (lock) {
@@ -640,8 +640,10 @@
 
     @Override
     public void put(String key, String value) {
-        if (key == null || value == null) {
-            throw new NullPointerException();
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        } else if (value == null) {
+            throw new NullPointerException("value == null");
         }
         if (key.length() > MAX_KEY_LENGTH || value.length() > MAX_VALUE_LENGTH) {
             throw new IllegalArgumentException();
@@ -730,7 +732,7 @@
     @Override
     public void addNodeChangeListener(NodeChangeListener ncl) {
         if (ncl == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("ncl == null");
         }
         checkState();
         synchronized (nodeChangeListeners) {
@@ -741,7 +743,7 @@
     @Override
     public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
         if (pcl == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("pcl == null");
         }
         checkState();
         synchronized (preferenceChangeListeners) {
diff --git a/luni/src/main/java/java/util/regex/Matcher.java b/luni/src/main/java/java/util/regex/Matcher.java
index 58bcf9e..cfd4432 100644
--- a/luni/src/main/java/java/util/regex/Matcher.java
+++ b/luni/src/main/java/java/util/regex/Matcher.java
@@ -50,11 +50,6 @@
     private int regionEnd;
 
     /**
-     * Holds the position where the next find operation will take place.
-     */
-    private int findPos;
-
-    /**
      * Holds the position where the next append operation will take place.
      */
     private int appendPos;
@@ -212,7 +207,6 @@
         resetForInput();
 
         matchFound = false;
-        findPos = regionStart;
         appendPos = 0;
 
         return this;
@@ -377,30 +371,17 @@
     }
 
     /**
-     * Returns the next occurrence of the {@link Pattern} in the input. The
-     * method starts the search from the given character in the input.
+     * Returns true if there is another match in the input, starting
+     * from the given position. The region is ignored.
      *
-     * @param start
-     *            The index in the input at which the find operation is to
-     *            begin. If this is less than the start of the region, it is
-     *            automatically adjusted to that value. If it is beyond the end
-     *            of the region, the method will fail.
-     * @return true if (and only if) a match has been found.
+     * @throws IndexOutOfBoundsException if {@code start < 0 || start > input.length()}
      */
     public boolean find(int start) {
-        findPos = start;
-
-        if (findPos < regionStart) {
-            findPos = regionStart;
-        } else if (findPos >= regionEnd) {
-            matchFound = false;
-            return false;
+        if (start < 0 || start > input.length()) {
+            throw new IndexOutOfBoundsException("start=" + start + "; length=" + input.length());
         }
 
-        matchFound = findImpl(address, input, findPos, matchOffsets);
-        if (matchFound) {
-            findPos = matchOffsets[1];
-        }
+        matchFound = findImpl(address, input, start, matchOffsets);
         return matchFound;
     }
 
@@ -414,9 +395,6 @@
      */
     public boolean find() {
         matchFound = findNextImpl(address, input, matchOffsets);
-        if (matchFound) {
-            findPos = matchOffsets[1];
-        }
         return matchFound;
     }
 
@@ -429,9 +407,6 @@
      */
     public boolean lookingAt() {
         matchFound = lookingAtImpl(address, input, matchOffsets);
-        if (matchFound) {
-            findPos = matchOffsets[1];
-        }
         return matchFound;
     }
 
@@ -444,9 +419,6 @@
      */
     public boolean matches() {
         matchFound = matchesImpl(address, input, matchOffsets);
-        if (matchFound) {
-            findPos = matchOffsets[1];
-        }
         return matchFound;
     }
 
diff --git a/luni/src/main/java/java/util/regex/Pattern.java b/luni/src/main/java/java/util/regex/Pattern.java
index 46984b9..cbd5965 100644
--- a/luni/src/main/java/java/util/regex/Pattern.java
+++ b/luni/src/main/java/java/util/regex/Pattern.java
@@ -82,16 +82,23 @@
  * </table>
  * <p>Most of the time, the built-in character classes are more useful:
  * <table>
- * <tr> <td> \d </td> <td>Any digit character.</td> </tr>
- * <tr> <td> \D </td> <td>Any non-digit character.</td> </tr>
- * <tr> <td> \s </td> <td>Any whitespace character.</td> </tr>
- * <tr> <td> \S </td> <td>Any non-whitespace character.</td> </tr>
- * <tr> <td> \w </td> <td>Any word character.</td> </tr>
- * <tr> <td> \W </td> <td>Any non-word character.</td> </tr>
+ * <tr> <td> \d </td> <td>Any digit character (see note below).</td> </tr>
+ * <tr> <td> \D </td> <td>Any non-digit character (see note below).</td> </tr>
+ * <tr> <td> \s </td> <td>Any whitespace character (see note below).</td> </tr>
+ * <tr> <td> \S </td> <td>Any non-whitespace character (see note below).</td> </tr>
+ * <tr> <td> \w </td> <td>Any word character (see note below).</td> </tr>
+ * <tr> <td> \W </td> <td>Any non-word character (see note below).</td> </tr>
  * <tr> <td> \p{<i>NAME</i>} </td> <td> Any character in the class with the given <i>NAME</i>. </td> </tr>
  * <tr> <td> \P{<i>NAME</i>} </td> <td> Any character <i>not</i> in the named class. </td> </tr>
  * </table>
- * <p>There are a variety of named classes:
+ * <p>Note that these built-in classes don't just cover the traditional ASCII range. For example,
+ * <code>\w</code> is equivalent to the character class <code>[\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}]</code>.
+ * For more details see <a href="http://www.unicode.org/reports/tr18/#Compatibility_Properties">Unicode TR-18</a>,
+ * and bear in mind that the set of characters in each class can vary between Unicode releases.
+ * If you actually want to match only ASCII characters, specify the explicit characters you want;
+ * if you mean 0-9 use <code>[0-9]</code> rather than <code>\d</code>, which would also include
+ * Gurmukhi digits and so forth.
+ * <p>There are also a variety of named classes:
  * <ul>
  * <li><a href="../../lang/Character.html#unicode_categories">Unicode category names</a>,
  * prefixed by {@code Is}. For example {@code \p{IsLu}} for all uppercase letters.
diff --git a/luni/src/main/java/java/util/zip/DeflaterInputStream.java b/luni/src/main/java/java/util/zip/DeflaterInputStream.java
index c6e95f2..805ce17 100644
--- a/luni/src/main/java/java/util/zip/DeflaterInputStream.java
+++ b/luni/src/main/java/java/util/zip/DeflaterInputStream.java
@@ -72,8 +72,10 @@
      */
     public DeflaterInputStream(InputStream in, Deflater deflater, int bufferSize) {
         super(in);
-        if (in == null || deflater == null) {
-            throw new NullPointerException();
+        if (in == null) {
+            throw new NullPointerException("in == null");
+        } else if (deflater == null) {
+            throw new NullPointerException("deflater == null");
         }
         if (bufferSize <= 0) {
             throw new IllegalArgumentException();
diff --git a/luni/src/main/java/java/util/zip/DeflaterOutputStream.java b/luni/src/main/java/java/util/zip/DeflaterOutputStream.java
index b0bcb99..d336e72 100644
--- a/luni/src/main/java/java/util/zip/DeflaterOutputStream.java
+++ b/luni/src/main/java/java/util/zip/DeflaterOutputStream.java
@@ -115,8 +115,10 @@
      */
     public DeflaterOutputStream(OutputStream os, Deflater def, int bsize, boolean syncFlush) {
         super(os);
-        if (os == null || def == null) {
-            throw new NullPointerException();
+        if (os == null) {
+            throw new NullPointerException("os == null");
+        } else if (def == null) {
+            throw new NullPointerException("def == null");
         }
         if (bsize <= 0) {
             throw new IllegalArgumentException();
diff --git a/luni/src/main/java/java/util/zip/InflaterInputStream.java b/luni/src/main/java/java/util/zip/InflaterInputStream.java
index 580d605..6081037 100644
--- a/luni/src/main/java/java/util/zip/InflaterInputStream.java
+++ b/luni/src/main/java/java/util/zip/InflaterInputStream.java
@@ -103,8 +103,10 @@
      */
     public InflaterInputStream(InputStream is, Inflater inflater, int bsize) {
         super(is);
-        if (is == null || inflater == null) {
-            throw new NullPointerException();
+        if (is == null) {
+            throw new NullPointerException("is == null");
+        } else if (inflater == null) {
+            throw new NullPointerException("inflater == null");
         }
         if (bsize <= 0) {
             throw new IllegalArgumentException();
diff --git a/luni/src/main/java/java/util/zip/InflaterOutputStream.java b/luni/src/main/java/java/util/zip/InflaterOutputStream.java
index c9687b6..9a699a8 100644
--- a/luni/src/main/java/java/util/zip/InflaterOutputStream.java
+++ b/luni/src/main/java/java/util/zip/InflaterOutputStream.java
@@ -70,8 +70,10 @@
      */
     public InflaterOutputStream(OutputStream out, Inflater inf, int bufferSize) {
         super(out);
-        if (out == null || inf == null) {
-            throw new NullPointerException();
+        if (out == null) {
+            throw new NullPointerException("out == null");
+        } else if (inf == null) {
+            throw new NullPointerException("inf == null");
         }
         if (bufferSize <= 0) {
             throw new IllegalArgumentException();
diff --git a/luni/src/main/java/java/util/zip/ZipEntry.java b/luni/src/main/java/java/util/zip/ZipEntry.java
index b5d5b36..19680df 100644
--- a/luni/src/main/java/java/util/zip/ZipEntry.java
+++ b/luni/src/main/java/java/util/zip/ZipEntry.java
@@ -72,7 +72,7 @@
      */
     public ZipEntry(String name) {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
         if (name.length() > 0xFFFF) {
             throw new IllegalArgumentException("Name too long: " + name.length());
diff --git a/luni/src/main/java/java/util/zip/ZipFile.java b/luni/src/main/java/java/util/zip/ZipFile.java
index b538177..a79984c 100644
--- a/luni/src/main/java/java/util/zip/ZipFile.java
+++ b/luni/src/main/java/java/util/zip/ZipFile.java
@@ -239,7 +239,7 @@
     public ZipEntry getEntry(String entryName) {
         checkNotClosed();
         if (entryName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("entryName == null");
         }
 
         ZipEntry ze = mEntries.get(entryName);
diff --git a/luni/src/main/java/java/util/zip/ZipInputStream.java b/luni/src/main/java/java/util/zip/ZipInputStream.java
index 788e90b..019e878 100644
--- a/luni/src/main/java/java/util/zip/ZipInputStream.java
+++ b/luni/src/main/java/java/util/zip/ZipInputStream.java
@@ -101,7 +101,7 @@
     public ZipInputStream(InputStream stream) {
         super(new PushbackInputStream(stream, BUF_SIZE), new Inflater(true));
         if (stream == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("stream == null");
         }
     }
 
diff --git a/luni/src/main/java/javax/crypto/Cipher.java b/luni/src/main/java/javax/crypto/Cipher.java
index 1dacd46..aeb5def 100644
--- a/luni/src/main/java/javax/crypto/Cipher.java
+++ b/luni/src/main/java/javax/crypto/Cipher.java
@@ -141,10 +141,10 @@
     protected Cipher(CipherSpi cipherSpi, Provider provider,
             String transformation) {
         if (cipherSpi == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("cipherSpi == null");
         }
         if (!(cipherSpi instanceof NullCipherSpi) && provider == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("provider == null");
         }
         this.provider = provider;
         this.transformation = transformation;
@@ -1332,7 +1332,7 @@
     public static final int getMaxAllowedKeyLength(String transformation)
             throws NoSuchAlgorithmException {
         if (transformation == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("transformation == null");
         }
         checkTransformation(transformation);
         //FIXME jurisdiction policy files
@@ -1356,7 +1356,7 @@
     public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
             String transformation) throws NoSuchAlgorithmException {
         if (transformation == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("transformation == null");
         }
         checkTransformation(transformation);
         //FIXME jurisdiction policy files
diff --git a/luni/src/main/java/javax/crypto/CipherInputStream.java b/luni/src/main/java/javax/crypto/CipherInputStream.java
index 39dcfda..a59a425 100644
--- a/luni/src/main/java/javax/crypto/CipherInputStream.java
+++ b/luni/src/main/java/javax/crypto/CipherInputStream.java
@@ -135,7 +135,7 @@
     @Override
     public int read(byte[] buf, int off, int len) throws IOException {
         if (in == null) {
-            throw new NullPointerException("Underlying input stream is null");
+            throw new NullPointerException("in == null");
         }
 
         int i;
diff --git a/luni/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java b/luni/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
index 034f07a..0fb5b76 100644
--- a/luni/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
+++ b/luni/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
@@ -121,7 +121,7 @@
      * Creates an {@code EncryptedPrivateKeyInfo} instance from an algorithm
      * name and its encrypted data.
      *
-     * @param encrAlgName
+     * @param encryptionAlgorithmName
      *            the name of an algorithm.
      * @param encryptedData
      *            the encrypted data.
@@ -133,12 +133,12 @@
      * @throws IllegalArgumentException
      *             if {@code encryptedData} is empty.
      */
-    public EncryptedPrivateKeyInfo(String encrAlgName, byte[] encryptedData)
+    public EncryptedPrivateKeyInfo(String encryptionAlgorithmName, byte[] encryptedData)
         throws NoSuchAlgorithmException {
-        if (encrAlgName == null) {
-            throw new NullPointerException("the algName parameter is null");
+        if (encryptionAlgorithmName == null) {
+            throw new NullPointerException("encryptionAlgorithmName == null");
         }
-        this.algName = encrAlgName;
+        this.algName = encryptionAlgorithmName;
         if (!mapAlgName()) {
             throw new NoSuchAlgorithmException("Unsupported algorithm: " + this.algName);
         }
diff --git a/luni/src/main/java/javax/crypto/ExemptionMechanism.java b/luni/src/main/java/javax/crypto/ExemptionMechanism.java
index 2ac4994..8745b78 100644
--- a/luni/src/main/java/javax/crypto/ExemptionMechanism.java
+++ b/luni/src/main/java/javax/crypto/ExemptionMechanism.java
@@ -98,7 +98,7 @@
     public static final ExemptionMechanism getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new ExemptionMechanism((ExemptionMechanismSpi) sap.spi, sap.provider, algorithm);
@@ -134,7 +134,7 @@
             throw new NoSuchProviderException(provider);
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         return getInstance(algorithm, impProvider);
     }
@@ -159,7 +159,7 @@
     public static final ExemptionMechanism getInstance(String algorithm,
             Provider provider) throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         if (provider == null) {
             throw new IllegalArgumentException("provider == null");
diff --git a/luni/src/main/java/javax/crypto/KeyAgreement.java b/luni/src/main/java/javax/crypto/KeyAgreement.java
index 9c5d86c..51b4cd1 100644
--- a/luni/src/main/java/javax/crypto/KeyAgreement.java
+++ b/luni/src/main/java/javax/crypto/KeyAgreement.java
@@ -99,7 +99,7 @@
     public static final KeyAgreement getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new KeyAgreement((KeyAgreementSpi) sap.spi, sap.provider, algorithm);
@@ -161,7 +161,7 @@
             throw new IllegalArgumentException("provider == null");
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new KeyAgreement((KeyAgreementSpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/javax/crypto/KeyGenerator.java b/luni/src/main/java/javax/crypto/KeyGenerator.java
index 77b1a82..606998a 100644
--- a/luni/src/main/java/javax/crypto/KeyGenerator.java
+++ b/luni/src/main/java/javax/crypto/KeyGenerator.java
@@ -98,7 +98,7 @@
     public static final KeyGenerator getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new KeyGenerator((KeyGeneratorSpi) sap.spi, sap.provider, algorithm);
@@ -158,7 +158,7 @@
             throw new IllegalArgumentException("provider == null");
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new KeyGenerator((KeyGeneratorSpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/javax/crypto/Mac.java b/luni/src/main/java/javax/crypto/Mac.java
index 1a05b59..46be141 100644
--- a/luni/src/main/java/javax/crypto/Mac.java
+++ b/luni/src/main/java/javax/crypto/Mac.java
@@ -101,7 +101,7 @@
     public static final Mac getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new Mac((MacSpi) sap.spi, sap.provider, algorithm);
@@ -163,7 +163,7 @@
             throw new IllegalArgumentException("provider == null");
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new Mac((MacSpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/javax/crypto/SealedObject.java b/luni/src/main/java/javax/crypto/SealedObject.java
index c9c1534..cfb970b 100644
--- a/luni/src/main/java/javax/crypto/SealedObject.java
+++ b/luni/src/main/java/javax/crypto/SealedObject.java
@@ -33,12 +33,12 @@
 /**
  * A {@code SealedObject} is a wrapper around a {@code serializable} object
  * instance and encrypts it using a cryptographic cipher.
- * <p>
- * Since a {@code SealedObject} instance is a serializable object itself it can
+ *
+ * <p>Since a {@code SealedObject} instance is serializable it can
  * either be stored or transmitted over an insecure channel.
- * <p>
- * The wrapped object can later be decrypted (unsealed) using the corresponding
- * key and then be deserialized to retrieve the original object.The sealed
+ *
+ * <p>The wrapped object can later be decrypted (unsealed) using the corresponding
+ * key and then be deserialized to retrieve the original object. The sealed
  * object itself keeps track of the cipher and corresponding parameters.
  */
 public class SealedObject implements Serializable {
@@ -46,19 +46,25 @@
     private static final long serialVersionUID = 4482838265551344752L;
 
     /**
-     * The {@link AlgorithmParameters} in encoded format.
+     * The cipher's {@link AlgorithmParameters} in encoded format.
+     * Equivalent to {@code cipher.getParameters().getEncoded()},
+     * or null if the cipher did not use any parameters.
      */
     protected byte[] encodedParams;
+
     private byte[] encryptedContent;
     private String sealAlg;
     private String paramsAlg;
 
-    private void readObject(ObjectInputStream s)
-                throws IOException, ClassNotFoundException {
-        encodedParams = (byte []) s.readUnshared();
-        encryptedContent = (byte []) s.readUnshared();
-        sealAlg = (String) s.readUnshared();
-        paramsAlg = (String) s.readUnshared();
+    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
+        // We do unshared reads here to ensure we have our own clones of the byte[]s.
+        encodedParams = (byte[]) s.readUnshared();
+        encryptedContent = (byte[]) s.readUnshared();
+        // These are regular shared reads because the algorithms used by a given stream are
+        // almost certain to the be same for each object, and String is immutable anyway,
+        // so there's no security concern about sharing.
+        sealAlg = (String) s.readObject();
+        paramsAlg = (String) s.readObject();
     }
 
     /**
diff --git a/luni/src/main/java/javax/crypto/SecretKeyFactory.java b/luni/src/main/java/javax/crypto/SecretKeyFactory.java
index 5e47abe1..8ab3eb8 100644
--- a/luni/src/main/java/javax/crypto/SecretKeyFactory.java
+++ b/luni/src/main/java/javax/crypto/SecretKeyFactory.java
@@ -103,7 +103,7 @@
     public static final SecretKeyFactory getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new SecretKeyFactory((SecretKeyFactorySpi) sap.spi, sap.provider, algorithm);
@@ -165,7 +165,7 @@
             throw new IllegalArgumentException("provider == null");
         }
         if (algorithm == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new SecretKeyFactory((SecretKeyFactorySpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/javax/crypto/spec/DESedeKeySpec.java b/luni/src/main/java/javax/crypto/spec/DESedeKeySpec.java
index fe86aeb..fcfe749 100644
--- a/luni/src/main/java/javax/crypto/spec/DESedeKeySpec.java
+++ b/luni/src/main/java/javax/crypto/spec/DESedeKeySpec.java
@@ -45,7 +45,7 @@
      */
     public DESedeKeySpec(byte[] key) throws InvalidKeyException {
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
         if (key.length < DES_EDE_KEY_LEN) {
             throw new InvalidKeyException();
@@ -71,7 +71,7 @@
      */
     public DESedeKeySpec(byte[] key, int offset) throws InvalidKeyException {
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
         if (key.length - offset < DES_EDE_KEY_LEN) {
             throw new InvalidKeyException();
diff --git a/luni/src/main/java/javax/crypto/spec/OAEPParameterSpec.java b/luni/src/main/java/javax/crypto/spec/OAEPParameterSpec.java
index 3bc9ab4..340e57f 100644
--- a/luni/src/main/java/javax/crypto/spec/OAEPParameterSpec.java
+++ b/luni/src/main/java/javax/crypto/spec/OAEPParameterSpec.java
@@ -73,8 +73,12 @@
      */
     public OAEPParameterSpec(String mdName, String mgfName,
                                 AlgorithmParameterSpec mgfSpec, PSource pSrc) {
-        if ((mdName == null) || (mgfName == null) || (pSrc == null)) {
-            throw new NullPointerException();
+        if (mdName == null) {
+            throw new NullPointerException("mdName == null");
+        } else if (mgfName == null) {
+            throw new NullPointerException("mgfName == null");
+        } else if (pSrc == null) {
+            throw new NullPointerException("pSrc == null");
         }
         this.mdName = mdName;
         this.mgfName = mgfName;
diff --git a/luni/src/main/java/javax/crypto/spec/PSource.java b/luni/src/main/java/javax/crypto/spec/PSource.java
index 0efa1e9..f644316 100644
--- a/luni/src/main/java/javax/crypto/spec/PSource.java
+++ b/luni/src/main/java/javax/crypto/spec/PSource.java
@@ -40,7 +40,7 @@
      */
     protected PSource(String pSrcName) {
         if (pSrcName == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("pSrcName == null");
         }
         this.pSrcName = pSrcName;
     }
@@ -85,7 +85,7 @@
         public PSpecified(byte[] p) {
             super("PSpecified");
             if (p == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("p == null");
             }
             //TODO: It is unknown which name should be used!
             //super("");
diff --git a/luni/src/main/java/javax/net/ssl/KeyManagerFactory.java b/luni/src/main/java/javax/net/ssl/KeyManagerFactory.java
index 82ce8a1..0b3db61 100644
--- a/luni/src/main/java/javax/net/ssl/KeyManagerFactory.java
+++ b/luni/src/main/java/javax/net/ssl/KeyManagerFactory.java
@@ -68,7 +68,7 @@
     public static final KeyManagerFactory getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException("algorithm is null");
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new KeyManagerFactory((KeyManagerFactorySpi) sap.spi, sap.provider, algorithm);
@@ -127,7 +127,7 @@
             throw new IllegalArgumentException("Provider is null");
         }
         if (algorithm == null) {
-            throw new NullPointerException("algorithm is null");
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new KeyManagerFactory((KeyManagerFactorySpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/javax/net/ssl/SSLContext.java b/luni/src/main/java/javax/net/ssl/SSLContext.java
index 9097bb9..a59f301 100644
--- a/luni/src/main/java/javax/net/ssl/SSLContext.java
+++ b/luni/src/main/java/javax/net/ssl/SSLContext.java
@@ -93,7 +93,7 @@
      */
     public static SSLContext getInstance(String protocol) throws NoSuchAlgorithmException {
         if (protocol == null) {
-            throw new NullPointerException("protocol is null");
+            throw new NullPointerException("protocol == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(protocol, null);
         return new SSLContext((SSLContextSpi) sap.spi, sap.provider, protocol);
@@ -154,7 +154,7 @@
             throw new IllegalArgumentException("provider is null");
         }
         if (protocol == null) {
-            throw new NullPointerException("protocol is null");
+            throw new NullPointerException("protocol == null");
         }
         Object spi = ENGINE.getInstance(protocol, provider, null);
         return new SSLContext((SSLContextSpi) spi, provider, protocol);
diff --git a/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java b/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java
index bf3bf8c..be9db06 100644
--- a/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java
+++ b/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java
@@ -67,7 +67,7 @@
     public static final TrustManagerFactory getInstance(String algorithm)
             throws NoSuchAlgorithmException {
         if (algorithm == null) {
-            throw new NullPointerException("algorithm is null");
+            throw new NullPointerException("algorithm == null");
         }
         Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
         return new TrustManagerFactory((TrustManagerFactorySpi) sap.spi, sap.provider, algorithm);
@@ -126,7 +126,7 @@
             throw new IllegalArgumentException("Provider is null");
         }
         if (algorithm == null) {
-            throw new NullPointerException("algorithm is null");
+            throw new NullPointerException("algorithm == null");
         }
         Object spi = ENGINE.getInstance(algorithm, provider, null);
         return new TrustManagerFactory((TrustManagerFactorySpi) spi, provider, algorithm);
diff --git a/luni/src/main/java/javax/security/auth/Subject.java b/luni/src/main/java/javax/security/auth/Subject.java
index a958484..6c9c036 100644
--- a/luni/src/main/java/javax/security/auth/Subject.java
+++ b/luni/src/main/java/javax/security/auth/Subject.java
@@ -116,8 +116,12 @@
     public Subject(boolean readOnly, Set<? extends Principal> subjPrincipals,
             Set<?> pubCredentials, Set<?> privCredentials) {
 
-        if (subjPrincipals == null || pubCredentials == null || privCredentials == null) {
-            throw new NullPointerException();
+        if (subjPrincipals == null) {
+            throw new NullPointerException("subjPrincipals == null");
+        } else if (pubCredentials == null) {
+            throw new NullPointerException("pubCredentials == null");
+        } else if (privCredentials == null) {
+            throw new NullPointerException("privCredentials == null");
         }
 
         principals = new SecureSet<Principal>(_PRINCIPALS, subjPrincipals);
@@ -467,7 +471,7 @@
      */
     public static Subject getSubject(final AccessControlContext context) {
         if (context == null) {
-            throw new NullPointerException("AccessControlContext cannot be null");
+            throw new NullPointerException("context == null");
         }
         PrivilegedAction<DomainCombiner> action = new PrivilegedAction<DomainCombiner>() {
             public DomainCombiner run() {
@@ -554,7 +558,7 @@
         private void verifyElement(Object o) {
 
             if (o == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("o == null");
             }
             if (permission == _PRINCIPALS && !(Principal.class.isAssignableFrom(o.getClass()))) {
                 throw new IllegalArgumentException("Element is not instance of java.security.Principal");
@@ -607,7 +611,7 @@
         public boolean retainAll(Collection<?> c) {
 
             if (c == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("c == null");
             }
             return super.retainAll(c);
         }
@@ -624,7 +628,7 @@
         protected final <E> Set<E> get(final Class<E> c) {
 
             if (c == null) {
-                throw new NullPointerException();
+                throw new NullPointerException("c == null");
             }
 
             AbstractSet<E> s = new AbstractSet<E>() {
@@ -652,7 +656,7 @@
                 public boolean retainAll(Collection<?> c) {
 
                     if (c == null) {
-                        throw new NullPointerException();
+                        throw new NullPointerException("c == null");
                     }
                     return super.retainAll(c);
                 }
diff --git a/luni/src/main/java/javax/security/auth/x500/X500Principal.java b/luni/src/main/java/javax/security/auth/x500/X500Principal.java
index e6453e9..cedebe0 100644
--- a/luni/src/main/java/javax/security/auth/x500/X500Principal.java
+++ b/luni/src/main/java/javax/security/auth/x500/X500Principal.java
@@ -123,7 +123,7 @@
      */
     public X500Principal(String name) {
         if (name == null) {
-            throw new NullPointerException("Name cannot be null");
+            throw new NullPointerException("name == null");
         }
         try {
             dn = new Name(name);
@@ -134,7 +134,7 @@
 
     public X500Principal(String name, Map<String,String> keywordMap){
         if (name == null) {
-            throw new NullPointerException("Name cannot be null");
+            throw new NullPointerException("name == null");
         }
         try {
             dn = new Name(substituteNameFromMap(name, keywordMap));
diff --git a/luni/src/main/java/javax/xml/datatype/DatatypeFactory.java b/luni/src/main/java/javax/xml/datatype/DatatypeFactory.java
index 6a89dae..68291b6 100644
--- a/luni/src/main/java/javax/xml/datatype/DatatypeFactory.java
+++ b/luni/src/main/java/javax/xml/datatype/DatatypeFactory.java
@@ -326,7 +326,7 @@
      */
     public Duration newDurationDayTime(final String lexicalRepresentation) {
         if (lexicalRepresentation == null) {
-            throw new NullPointerException("The lexical representation cannot be null.");
+            throw new NullPointerException("lexicalRepresentation == null");
         }
         // The lexical representation must match the pattern [^YM]*(T.*)?
         int pos = lexicalRepresentation.indexOf('T');
@@ -539,7 +539,7 @@
      */
     public Duration newDurationYearMonth(final String lexicalRepresentation) {
         if (lexicalRepresentation == null) {
-            throw new NullPointerException("The lexical representation cannot be null.");
+            throw new NullPointerException("lexicalRepresentation == null");
         }
         // The lexical representation must match the pattern [^DT]*.
         int length = lexicalRepresentation.length();
diff --git a/luni/src/main/java/javax/xml/datatype/Duration.java b/luni/src/main/java/javax/xml/datatype/Duration.java
index 8121d36..fcdd4c5 100644
--- a/luni/src/main/java/javax/xml/datatype/Duration.java
+++ b/luni/src/main/java/javax/xml/datatype/Duration.java
@@ -552,11 +552,7 @@
 
         // check data parameter
         if (date == null) {
-            throw new NullPointerException(
-                    "Cannot call "
-                    + this.getClass().getName()
-                    + "#addTo(Date date) with date == null."
-            );
+            throw new NullPointerException("date == null");
         }
 
         Calendar cal = new GregorianCalendar();
diff --git a/luni/src/main/java/javax/xml/namespace/QName.java b/luni/src/main/java/javax/xml/namespace/QName.java
index f748b64..a82487f 100644
--- a/luni/src/main/java/javax/xml/namespace/QName.java
+++ b/luni/src/main/java/javax/xml/namespace/QName.java
@@ -22,8 +22,6 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import javax.xml.XMLConstants;
 
 /**
diff --git a/luni/src/main/java/javax/xml/validation/SchemaFactory.java b/luni/src/main/java/javax/xml/validation/SchemaFactory.java
index 23e4798..2018067 100644
--- a/luni/src/main/java/javax/xml/validation/SchemaFactory.java
+++ b/luni/src/main/java/javax/xml/validation/SchemaFactory.java
@@ -203,8 +203,10 @@
      */
     public static SchemaFactory newInstance(String schemaLanguage, String factoryClassName,
             ClassLoader classLoader) {
-        if (schemaLanguage == null || factoryClassName == null) {
-            throw new NullPointerException("schemaLanguage == null || factoryClassName == null");
+        if (schemaLanguage == null) {
+            throw new NullPointerException("schemaLanguage == null");
+        } else if (factoryClassName == null) {
+            throw new NullPointerException("factoryClassName == null");
         }
         if (classLoader == null) {
             classLoader = Thread.currentThread().getContextClassLoader();
@@ -265,7 +267,7 @@
     public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
 
         if (name == null) {
-            throw new NullPointerException("the name parameter is null");
+            throw new NullPointerException("name == null");
         }
         throw new SAXNotRecognizedException(name);
     }
@@ -313,7 +315,7 @@
      */
     public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
         if (name == null) {
-            throw new NullPointerException("the name parameter is null");
+            throw new NullPointerException("name == null");
         }
         throw new SAXNotRecognizedException(name);
     }
@@ -340,7 +342,7 @@
      */
     public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException {
         if (name == null) {
-            throw new NullPointerException("the name parameter is null");
+            throw new NullPointerException("name == null");
         }
         throw new SAXNotRecognizedException(name);
     }
@@ -371,7 +373,7 @@
      */
     public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
         if (name == null) {
-            throw new NullPointerException("the name parameter is null");
+            throw new NullPointerException("name == null");
         }
         throw new SAXNotRecognizedException(name);
     }
diff --git a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
index 3a6cb83..636777c 100644
--- a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
@@ -131,7 +131,9 @@
      *      If the <tt>schemaLanguage</tt> parameter is null.
      */
     public SchemaFactory newFactory(String schemaLanguage) {
-        if(schemaLanguage==null)        throw new NullPointerException();
+        if (schemaLanguage == null) {
+            throw new NullPointerException("schemaLanguage == null");
+        }
         SchemaFactory f = _newFactory(schemaLanguage);
         if (debug) {
             if (f != null) {
diff --git a/luni/src/main/java/javax/xml/validation/Validator.java b/luni/src/main/java/javax/xml/validation/Validator.java
index b4ee1ca..ea7908a 100644
--- a/luni/src/main/java/javax/xml/validation/Validator.java
+++ b/luni/src/main/java/javax/xml/validation/Validator.java
@@ -339,7 +339,9 @@
      * @see #setFeature(String, boolean)
      */
     public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
-        if(name==null) throw new NullPointerException("the name parameter is null");
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
         throw new SAXNotRecognizedException(name);
     }
 
@@ -372,7 +374,9 @@
      * @see #getFeature(String)
      */
     public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
-        if(name==null) throw new NullPointerException("the name parameter is null");
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
         throw new SAXNotRecognizedException(name);
     }
 
@@ -400,7 +404,9 @@
      *          When the name parameter is null.
      */
     public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException {
-        if(name==null) throw new NullPointerException("the name parameter is null");
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
         throw new SAXNotRecognizedException(name);
     }
 
@@ -431,7 +437,9 @@
      * @see #setProperty(String, Object)
      */
     public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
-        if(name==null) throw new NullPointerException("the name parameter is null");
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
         throw new SAXNotRecognizedException(name);
     }
 }
diff --git a/luni/src/main/java/javax/xml/validation/ValidatorHandler.java b/luni/src/main/java/javax/xml/validation/ValidatorHandler.java
index 9606193..2b621ff 100644
--- a/luni/src/main/java/javax/xml/validation/ValidatorHandler.java
+++ b/luni/src/main/java/javax/xml/validation/ValidatorHandler.java
@@ -347,8 +347,9 @@
      * @see #setFeature(String, boolean)
      */
     public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
-        if(name==null)
-            throw new NullPointerException();
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
         throw new SAXNotRecognizedException(name);
     }
 
@@ -381,8 +382,9 @@
      * @see #getFeature(String)
      */
     public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
-        if(name==null)
-            throw new NullPointerException();
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
         throw new SAXNotRecognizedException(name);
     }
 
@@ -411,8 +413,9 @@
      *          When the name parameter is null.
      */
     public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException {
-        if(name==null)
-            throw new NullPointerException();
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
         throw new SAXNotRecognizedException(name);
     }
 
@@ -443,8 +446,9 @@
      * @see #setProperty(String, Object)
      */
     public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
-        if(name==null)
-            throw new NullPointerException();
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
         throw new SAXNotRecognizedException(name);
     }
 }
diff --git a/luni/src/main/java/javax/xml/xpath/XPathException.java b/luni/src/main/java/javax/xml/xpath/XPathException.java
index 8db369b..376d477 100644
--- a/luni/src/main/java/javax/xml/xpath/XPathException.java
+++ b/luni/src/main/java/javax/xml/xpath/XPathException.java
@@ -48,8 +48,8 @@
      */
     public XPathException(String message) {
         super(message);
-        if ( message == null ) {
-            throw new NullPointerException ( "message can't be null");
+        if (message == null) {
+            throw new NullPointerException("message == null");
         }
         this.cause = null;
     }
@@ -66,8 +66,8 @@
     public XPathException(Throwable cause) {
         super(cause == null ? null : cause.toString());
         this.cause = cause;
-        if ( cause == null ) {
-            throw new NullPointerException ( "cause can't be null");
+        if (cause == null) {
+            throw new NullPointerException("cause == null");
         }
     }
 
diff --git a/luni/src/main/java/javax/xml/xpath/XPathFactory.java b/luni/src/main/java/javax/xml/xpath/XPathFactory.java
index 8b1c1fa..57f2195 100644
--- a/luni/src/main/java/javax/xml/xpath/XPathFactory.java
+++ b/luni/src/main/java/javax/xml/xpath/XPathFactory.java
@@ -133,9 +133,7 @@
     public static final XPathFactory newInstance(final String uri)
         throws XPathFactoryConfigurationException {
         if (uri == null) {
-            throw new NullPointerException(
-                "XPathFactory#newInstance(String uri) cannot be called with uri == null"
-            );
+            throw new NullPointerException("uri == null");
         }
         if (uri.length() == 0) {
             throw new IllegalArgumentException(
@@ -167,9 +165,7 @@
     public static XPathFactory newInstance(String uri, String factoryClassName,
             ClassLoader classLoader) throws XPathFactoryConfigurationException {
         if (uri == null) {
-            throw new NullPointerException(
-                "XPathFactory#newInstance(String uri) cannot be called with uri == null"
-            );
+            throw new NullPointerException("uri == null");
         }
         if (uri.length() == 0) {
             throw new IllegalArgumentException(
diff --git a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
index 652a1d8..0113e7d 100644
--- a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
@@ -126,7 +126,9 @@
      *      If the parameter is null.
      */
     public XPathFactory newFactory(String uri) {
-        if(uri==null)        throw new NullPointerException();
+        if (uri == null) {
+            throw new NullPointerException("uri == null");
+        }
         XPathFactory f = _newFactory(uri);
         if (debug) {
             if (f != null) {
diff --git a/luni/src/main/java/javax/xml/xpath/package.html b/luni/src/main/java/javax/xml/xpath/package.html
index edeb448..202a29c 100644
--- a/luni/src/main/java/javax/xml/xpath/package.html
+++ b/luni/src/main/java/javax/xml/xpath/package.html
@@ -165,7 +165,7 @@
 XPath xpath = XPathFactory.newInstance().newXPath();
 String expression = "/widgets/widget";
 InputSource inputSource = new InputSource("widgets.xml");
-NodeSet nodes = (NodeSet) xpath.evaluate(expression, inputSource, XPathConstants.NODESET);
+NodeList nodes = (NodeList) xpath.evaluate(expression, inputSource, XPathConstants.NODESET);
 </pre>
 
 <h3>XPath Expressions and Types</h3>
diff --git a/luni/src/main/java/libcore/icu/ErrorCode.java b/luni/src/main/java/libcore/icu/ErrorCode.java
deleted file mode 100644
index c093af2..0000000
--- a/luni/src/main/java/libcore/icu/ErrorCode.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
-******************************************************************************
-* Copyright (C) 1996-2005, International Business Machines Corporation and   *
-* others. All Rights Reserved.                                               *
-******************************************************************************
-*
-******************************************************************************
-*/
-
-package libcore.icu;
-
-/**
- * Error exception class mapping ICU error codes of the enum UErrorCode
- * @author syn wee quek
-*/
-public final class ErrorCode extends Exception {
-    public static boolean isFailure(int error) {
-        return error > U_ZERO_ERROR && error < U_ERROR_LIMIT;
-    }
-
-    public static RuntimeException throwException(int error) {
-        if (error <= U_ZERO_ERROR && error >= U_ERROR_LIMIT) {
-            return null;
-        }
-        switch (error) {
-        case U_ILLEGAL_ARGUMENT_ERROR:
-            return new IllegalArgumentException(ERROR_NAMES[error]);
-        case U_INDEX_OUTOFBOUNDS_ERROR:
-        case U_BUFFER_OVERFLOW_ERROR:
-            return new ArrayIndexOutOfBoundsException(ERROR_NAMES[error]);
-        case U_UNSUPPORTED_ERROR:
-            return new UnsupportedOperationException(ERROR_NAMES[error]);
-        }
-        throw new RuntimeException(ERROR_NAMES[error]);
-    }
-
-    // The errors needed by our CharsetDecoderICU/CharsetEncoderICU.
-    public static final int U_ZERO_ERROR = 0;
-    private static final int U_ILLEGAL_ARGUMENT_ERROR = 1;
-    private static final int U_INDEX_OUTOFBOUNDS_ERROR = 8;
-    public static final int U_INVALID_CHAR_FOUND = 10;
-    public static final int U_TRUNCATED_CHAR_FOUND = 11;
-    public static final int U_ILLEGAL_CHAR_FOUND = 12;
-    public static final int U_BUFFER_OVERFLOW_ERROR = 15;
-    private static final int U_UNSUPPORTED_ERROR = 16;
-    private static final int U_ERROR_LIMIT = 21;
-
-    // TODO: this list is incomplete; get these from native code!
-    private static final String ERROR_NAMES[] = {
-        "U_ZERO_ERROR",
-        "U_ILLEGAL_ARGUMENT_ERROR",
-        "U_MISSING_RESOURCE_ERROR",
-        "U_INVALID_FORMAT_ERROR",
-        "U_FILE_ACCESS_ERROR",
-        "U_INTERNAL_PROGRAM_ERROR",
-        "U_MESSAGE_PARSE_ERROR",
-        "U_MEMORY_ALLOCATION_ERROR",
-        "U_INDEX_OUTOFBOUNDS_ERROR",
-        "U_PARSE_ERROR",
-        "U_INVALID_CHAR_FOUND",
-        "U_TRUNCATED_CHAR_FOUND",
-        "U_ILLEGAL_CHAR_FOUND",
-        "U_INVALID_TABLE_FORMAT",
-        "U_INVALID_TABLE_FILE",
-        "U_BUFFER_OVERFLOW_ERROR",
-        "U_UNSUPPORTED_ERROR",
-        "U_RESOURCE_TYPE_MISMATCH",
-        "U_ILLEGAL_ESCAPE_SEQUENCE",
-        "U_UNSUPPORTED_ESCAPE_SEQUENCE"
-    };
-}
diff --git a/luni/src/main/java/libcore/icu/ICU.java b/luni/src/main/java/libcore/icu/ICU.java
index 7f3303e..9984414 100644
--- a/luni/src/main/java/libcore/icu/ICU.java
+++ b/luni/src/main/java/libcore/icu/ICU.java
@@ -142,6 +142,19 @@
     public static native String toLowerCase(String s, String localeName);
     public static native String toUpperCase(String s, String localeName);
 
+    // --- Errors.
+
+    // Just the subset of error codes needed by CharsetDecoderICU/CharsetEncoderICU.
+    public static final int U_ZERO_ERROR = 0;
+    public static final int U_INVALID_CHAR_FOUND = 10;
+    public static final int U_TRUNCATED_CHAR_FOUND = 11;
+    public static final int U_ILLEGAL_CHAR_FOUND = 12;
+    public static final int U_BUFFER_OVERFLOW_ERROR = 15;
+
+    public static boolean U_FAILURE(int error) {
+      return error > U_ZERO_ERROR;
+    }
+
     // --- Native methods accessing ICU's database.
 
     private static native String[] getAvailableBreakIteratorLocalesNative();
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index cb9c880..8ec2294 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -20,6 +20,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Locale;
+import libcore.util.Objects;
 
 /**
  * Passes locale-specific from ICU native code to Java.
@@ -46,18 +47,27 @@
     public Integer minimalDaysInFirstWeek;
 
     // Used by DateFormatSymbols.
-    public String[] amPm;
-    public String[] eras;
+    public String[] amPm; // "AM", "PM".
+    public String[] eras; // "BC", "AD".
 
-    public String[] longMonthNames;
-    public String[] shortMonthNames;
-    public String[] longStandAloneMonthNames;
-    public String[] shortStandAloneMonthNames;
+    public String[] longMonthNames; // "January", ...
+    public String[] shortMonthNames; // "Jan", ...
+    public String[] tinyMonthNames; // "J", ...
+    public String[] longStandAloneMonthNames; // "January", ...
+    public String[] shortStandAloneMonthNames; // "Jan", ...
+    public String[] tinyStandAloneMonthNames; // "J", ...
 
-    public String[] longWeekdayNames;
-    public String[] shortWeekdayNames;
-    public String[] longStandAloneWeekdayNames;
-    public String[] shortStandAloneWeekdayNames;
+    public String[] longWeekdayNames; // "Sunday", ...
+    public String[] shortWeekdayNames; // "Sun", ...
+    public String[] tinyWeekdayNames; // "S", ...
+    public String[] longStandAloneWeekdayNames; // "Sunday", ...
+    public String[] shortStandAloneWeekdayNames; // "Sun", ...
+    public String[] tinyStandAloneWeekdayNames; // "S", ...
+
+    // Used by frameworks/base DateSorter and DateUtils.
+    public String yesterday; // "Yesterday".
+    public String today; // "Today".
+    public String tomorrow; // "Tomorrow".
 
     public String fullTimeFormat;
     public String longTimeFormat;
@@ -120,44 +130,7 @@
     }
 
     @Override public String toString() {
-        return "LocaleData[" +
-                "firstDayOfWeek=" + firstDayOfWeek + "," +
-                "minimalDaysInFirstWeek=" + minimalDaysInFirstWeek + "," +
-                "amPm=" + Arrays.toString(amPm) + "," +
-                "eras=" + Arrays.toString(eras) + "," +
-                "longMonthNames=" + Arrays.toString(longMonthNames) + "," +
-                "shortMonthNames=" + Arrays.toString(shortMonthNames) + "," +
-                "longStandAloneMonthNames=" + Arrays.toString(longStandAloneMonthNames) + "," +
-                "shortStandAloneMonthNames=" + Arrays.toString(shortStandAloneMonthNames) + "," +
-                "longWeekdayNames=" + Arrays.toString(longWeekdayNames) + "," +
-                "shortWeekdayNames=" + Arrays.toString(shortWeekdayNames) + "," +
-                "longStandAloneWeekdayNames=" + Arrays.toString(longStandAloneWeekdayNames) + "," +
-                "shortStandAloneWeekdayNames=" + Arrays.toString(shortStandAloneWeekdayNames) + "," +
-                "fullTimeFormat=" + fullTimeFormat + "," +
-                "longTimeFormat=" + longTimeFormat + "," +
-                "mediumTimeFormat=" + mediumTimeFormat + "," +
-                "shortTimeFormat=" + shortTimeFormat + "," +
-                "fullDateFormat=" + fullDateFormat + "," +
-                "longDateFormat=" + longDateFormat + "," +
-                "mediumDateFormat=" + mediumDateFormat + "," +
-                "shortDateFormat=" + shortDateFormat + "," +
-                "zeroDigit=" + zeroDigit + "," +
-                "decimalSeparator=" + decimalSeparator + "," +
-                "groupingSeparator=" + groupingSeparator + "," +
-                "patternSeparator=" + patternSeparator + "," +
-                "percent=" + percent + "," +
-                "perMill=" + perMill + "," +
-                "monetarySeparator=" + monetarySeparator + "," +
-                "minusSign=" + minusSign + "," +
-                "exponentSeparator=" + exponentSeparator + "," +
-                "infinity=" + infinity + "," +
-                "NaN=" + NaN + "," +
-                "currencySymbol=" + currencySymbol + "," +
-                "internationalCurrencySymbol=" + internationalCurrencySymbol + "," +
-                "numberPattern=" + numberPattern + "," +
-                "integerPattern=" + integerPattern + "," +
-                "currencyPattern=" + currencyPattern + "," +
-                "percentPattern=" + percentPattern + "]";
+        return Objects.toString(this);
     }
 
     public String getDateFormat(int style) {
diff --git a/luni/src/main/java/libcore/icu/NativeConverter.java b/luni/src/main/java/libcore/icu/NativeConverter.java
index 2d8630c..e18f483 100644
--- a/luni/src/main/java/libcore/icu/NativeConverter.java
+++ b/luni/src/main/java/libcore/icu/NativeConverter.java
@@ -54,19 +54,19 @@
         }
     }
 
-    public static int setCallbackDecode(long converterHandle, CharsetDecoder decoder) {
-        return setCallbackDecode(converterHandle,
-                translateCodingErrorAction(decoder.malformedInputAction()),
-                translateCodingErrorAction(decoder.unmappableCharacterAction()),
-                decoder.replacement());
+    public static void setCallbackDecode(long converterHandle, CharsetDecoder decoder) {
+        setCallbackDecode(converterHandle,
+                          translateCodingErrorAction(decoder.malformedInputAction()),
+                          translateCodingErrorAction(decoder.unmappableCharacterAction()),
+                          decoder.replacement());
     }
-    private static native int setCallbackDecode(long converterHandle, int onMalformedInput, int onUnmappableInput, String subChars);
+    private static native void setCallbackDecode(long converterHandle, int onMalformedInput, int onUnmappableInput, String subChars);
 
-    public static int setCallbackEncode(long converterHandle, CharsetEncoder encoder) {
-        return setCallbackEncode(converterHandle,
-                translateCodingErrorAction(encoder.malformedInputAction()),
-                translateCodingErrorAction(encoder.unmappableCharacterAction()),
-                encoder.replacement());
+    public static void setCallbackEncode(long converterHandle, CharsetEncoder encoder) {
+        setCallbackEncode(converterHandle,
+                          translateCodingErrorAction(encoder.malformedInputAction()),
+                          translateCodingErrorAction(encoder.unmappableCharacterAction()),
+                          encoder.replacement());
     }
-    private static native int setCallbackEncode(long converterHandle, int onMalformedInput, int onUnmappableInput, byte[] subBytes);
+    private static native void setCallbackEncode(long converterHandle, int onMalformedInput, int onUnmappableInput, byte[] subBytes);
 }
diff --git a/luni/src/main/java/libcore/icu/NativeDecimalFormat.java b/luni/src/main/java/libcore/icu/NativeDecimalFormat.java
index 74775e5..f6b5214 100644
--- a/luni/src/main/java/libcore/icu/NativeDecimalFormat.java
+++ b/luni/src/main/java/libcore/icu/NativeDecimalFormat.java
@@ -29,7 +29,7 @@
 import java.util.Currency;
 import java.util.NoSuchElementException;
 
-public final class NativeDecimalFormat {
+public final class NativeDecimalFormat implements Cloneable {
     /**
      * Constants corresponding to the native type UNumberFormatSymbol, for setSymbol.
      */
@@ -144,22 +144,6 @@
         this.lastPattern = pattern;
     }
 
-    // Used to implement clone.
-    private NativeDecimalFormat(NativeDecimalFormat other) {
-        this.address = cloneImpl(other.address);
-        this.lastPattern = other.lastPattern;
-        this.negPrefNull = other.negPrefNull;
-        this.negSuffNull = other.negSuffNull;
-        this.posPrefNull = other.posPrefNull;
-        this.posSuffNull = other.posSuffNull;
-    }
-
-    // TODO: remove this and just have DecimalFormat.hashCode do the right thing itself.
-    @Override
-    public int hashCode() {
-        return this.getPositivePrefix().hashCode();
-    }
-
     public synchronized void close() {
         if (address != 0) {
             close(address);
@@ -167,9 +151,27 @@
         }
     }
 
-    @Override
-    public Object clone() {
-        return new NativeDecimalFormat(this);
+    @Override protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override public Object clone() {
+        try {
+            NativeDecimalFormat clone = (NativeDecimalFormat) super.clone();
+            clone.address = cloneImpl(address);
+            clone.lastPattern = lastPattern;
+            clone.negPrefNull = negPrefNull;
+            clone.negSuffNull = negSuffNull;
+            clone.posPrefNull = posPrefNull;
+            clone.posSuffNull = posSuffNull;
+            return clone;
+        } catch (CloneNotSupportedException unexpected) {
+            throw new AssertionError(unexpected);
+        }
     }
 
     /**
diff --git a/luni/src/main/java/libcore/icu/NativeIDN.java b/luni/src/main/java/libcore/icu/NativeIDN.java
index 9bf5cb1..db93379 100644
--- a/luni/src/main/java/libcore/icu/NativeIDN.java
+++ b/luni/src/main/java/libcore/icu/NativeIDN.java
@@ -34,7 +34,7 @@
 
     private static String convert(String s, int flags, boolean toAscii) {
         if (s == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("s == null");
         }
         return convertImpl(s, flags, toAscii);
     }
diff --git a/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java b/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java
index d036c98..4221fe6 100644
--- a/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java
+++ b/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java
@@ -46,7 +46,7 @@
 
     public RuleBasedCollatorICU(String rules) throws ParseException {
         if (rules == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("rules == null");
         }
         address = NativeCollation.openCollatorFromRules(rules, VALUE_OFF, VALUE_DEFAULT_STRENGTH);
     }
diff --git a/luni/src/main/java/libcore/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index 4f2858d..61c9765 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -50,7 +50,7 @@
         }
     }
 
-    @Override public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException {
+    @Override public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException {
         BlockGuard.getThreadPolicy().onNetwork();
         return tagSocket(os.accept(fd, peerAddress));
     }
@@ -80,7 +80,7 @@
         return linger.isOn() && linger.l_linger > 0;
     }
 
-    @Override public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException {
+    @Override public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException {
         BlockGuard.getThreadPolicy().onNetwork();
         os.connect(fd, address, port);
     }
@@ -154,22 +154,22 @@
         return os.readv(fd, buffers, offsets, byteCounts);
     }
 
-    @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException {
+    @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
         BlockGuard.getThreadPolicy().onNetwork();
         return os.recvfrom(fd, buffer, flags, srcAddress);
     }
 
-    @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException {
+    @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
         BlockGuard.getThreadPolicy().onNetwork();
         return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress);
     }
 
-    @Override public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException {
+    @Override public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
         BlockGuard.getThreadPolicy().onNetwork();
         return os.sendto(fd, buffer, flags, inetAddress, port);
     }
 
-    @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException {
+    @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
         // We permit datagrams without hostname lookups.
         if (inetAddress != null) {
             BlockGuard.getThreadPolicy().onNetwork();
diff --git a/luni/src/main/java/libcore/io/DiskLruCache.java b/luni/src/main/java/libcore/io/DiskLruCache.java
index 4699766..8338983 100644
--- a/luni/src/main/java/libcore/io/DiskLruCache.java
+++ b/luni/src/main/java/libcore/io/DiskLruCache.java
@@ -16,7 +16,6 @@
 
 package libcore.io;
 
-import java.io.BufferedInputStream;
 import java.io.BufferedWriter;
 import java.io.Closeable;
 import java.io.EOFException;
@@ -227,13 +226,14 @@
     }
 
     private void readJournal() throws IOException {
-        InputStream in = new BufferedInputStream(new FileInputStream(journalFile));
+        StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile),
+                Charsets.US_ASCII);
         try {
-            String magic = Streams.readAsciiLine(in);
-            String version = Streams.readAsciiLine(in);
-            String appVersionString = Streams.readAsciiLine(in);
-            String valueCountString = Streams.readAsciiLine(in);
-            String blank = Streams.readAsciiLine(in);
+            String magic = reader.readLine();
+            String version = reader.readLine();
+            String appVersionString = reader.readLine();
+            String valueCountString = reader.readLine();
+            String blank = reader.readLine();
             if (!MAGIC.equals(magic)
                     || !VERSION_1.equals(version)
                     || !Integer.toString(appVersion).equals(appVersionString)
@@ -245,13 +245,13 @@
 
             while (true) {
                 try {
-                    readJournalLine(Streams.readAsciiLine(in));
+                    readJournalLine(reader.readLine());
                 } catch (EOFException endOfJournal) {
                     break;
                 }
             }
         } finally {
-            IoUtils.closeQuietly(in);
+            IoUtils.closeQuietly(reader);
         }
     }
 
@@ -458,9 +458,14 @@
         // if this edit is creating the entry for the first time, every index must have a value
         if (success && !entry.readable) {
             for (int i = 0; i < valueCount; i++) {
+                if (!editor.written[i]) {
+                    editor.abort();
+                    throw new IllegalStateException("Newly created entry didn't create value for index " + i);
+                }
                 if (!entry.getDirtyFile(i).exists()) {
                     editor.abort();
-                    throw new IllegalStateException("edit didn't create file " + i);
+                    System.logW("DiskLruCache: Newly created entry doesn't have file for index " + i);
+                    return;
                 }
             }
         }
@@ -659,10 +664,12 @@
      */
     public final class Editor {
         private final Entry entry;
+        private final boolean[] written;
         private boolean hasErrors;
 
         private Editor(Entry entry) {
             this.entry = entry;
+            this.written = (entry.readable) ? null : new boolean[valueCount];
         }
 
         /**
@@ -702,6 +709,9 @@
                 if (entry.currentEditor != this) {
                     throw new IllegalStateException();
                 }
+                if (!entry.readable) {
+                    written[index] = true;
+                }
                 return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index)));
             }
         }
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index 2c8e562..719c5f0 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -20,6 +20,7 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
+import java.net.SocketException;
 import java.nio.ByteBuffer;
 import libcore.util.MutableInt;
 import libcore.util.MutableLong;
@@ -34,15 +35,18 @@
         this.os = os;
     }
 
-    public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException { return os.accept(fd, peerAddress); }
+    public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException { return os.accept(fd, peerAddress); }
     public boolean access(String path, int mode) throws ErrnoException { return os.access(path, mode); }
-    public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException { os.bind(fd, address, port); }
+    public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.bind(fd, address, port); }
     public void chmod(String path, int mode) throws ErrnoException { os.chmod(path, mode); }
+    public void chown(String path, int uid, int gid) throws ErrnoException { os.chown(path, uid, gid); }
     public void close(FileDescriptor fd) throws ErrnoException { os.close(fd); }
-    public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException { os.connect(fd, address, port); }
+    public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.connect(fd, address, port); }
     public FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException { return os.dup(oldFd); }
     public FileDescriptor dup2(FileDescriptor oldFd, int newFd) throws ErrnoException { return os.dup2(oldFd, newFd); }
     public String[] environ() { return os.environ(); }
+    public void fchmod(FileDescriptor fd, int mode) throws ErrnoException { os.fchmod(fd, mode); }
+    public void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException { os.fchown(fd, uid, gid); }
     public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException { return os.fcntlVoid(fd, cmd); }
     public int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException { return os.fcntlLong(fd, cmd, arg); }
     public int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException { return os.fcntlFlock(fd, cmd, arg); }
@@ -75,6 +79,7 @@
     public int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException { return os.ioctlInt(fd, cmd, arg); }
     public boolean isatty(FileDescriptor fd) { return os.isatty(fd); }
     public void kill(int pid, int signal) throws ErrnoException { os.kill(pid, signal); }
+    public void lchown(String path, int uid, int gid) throws ErrnoException { os.lchown(path, uid, gid); }
     public void listen(FileDescriptor fd, int backlog) throws ErrnoException { os.listen(fd, backlog); }
     public long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException { return os.lseek(fd, offset, whence); }
     public StructStat lstat(String path) throws ErrnoException { return os.lstat(path); }
@@ -95,16 +100,17 @@
     public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { return os.read(fd, buffer); }
     public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException { return os.read(fd, bytes, byteOffset, byteCount); }
     public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException { return os.readv(fd, buffers, offsets, byteCounts); }
-    public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException { return os.recvfrom(fd, buffer, flags, srcAddress); }
-    public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException { return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress); }
+    public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { return os.recvfrom(fd, buffer, flags, srcAddress); }
+    public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { return os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress); }
     public void remove(String path) throws ErrnoException { os.remove(path); }
     public void rename(String oldPath, String newPath) throws ErrnoException { os.rename(oldPath, newPath); }
     public long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException { return os.sendfile(outFd, inFd, inOffset, byteCount); }
-    public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException { return os.sendto(fd, buffer, flags, inetAddress, port); }
-    public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException { return os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); }
+    public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { return os.sendto(fd, buffer, flags, inetAddress, port); }
+    public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { return os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); }
     public void setegid(int egid) throws ErrnoException { os.setegid(egid); }
     public void seteuid(int euid) throws ErrnoException { os.seteuid(euid); }
     public void setgid(int gid) throws ErrnoException { os.setgid(gid); }
+    public int setsid() throws ErrnoException { return os.setsid(); }
     public void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException { os.setsockoptByte(fd, level, option, value); }
     public void setsockoptIfreq(FileDescriptor fd, int level, int option, String value) throws ErrnoException { os.setsockoptIfreq(fd, level, option, value); }
     public void setsockoptInt(FileDescriptor fd, int level, int option, int value) throws ErrnoException { os.setsockoptInt(fd, level, option, value); }
@@ -120,6 +126,8 @@
     public String strerror(int errno) { return os.strerror(errno); }
     public void symlink(String oldPath, String newPath) throws ErrnoException { os.symlink(oldPath, newPath); }
     public long sysconf(int name) { return os.sysconf(name); }
+    public void tcdrain(FileDescriptor fd) throws ErrnoException { os.tcdrain(fd); }
+    public int umask(int mask) { return os.umask(mask); }
     public StructUtsname uname() { return os.uname(); }
     public int waitpid(int pid, MutableInt status, int options) throws ErrnoException { return os.waitpid(pid, status, options); }
     public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException { return os.write(fd, buffer); }
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index d637b67..55588d8 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -20,20 +20,24 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
+import java.net.SocketException;
 import java.nio.ByteBuffer;
 import libcore.util.MutableInt;
 import libcore.util.MutableLong;
 
 public interface Os {
-    public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException;
+    public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException;
     public boolean access(String path, int mode) throws ErrnoException;
-    public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
+    public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
     public void chmod(String path, int mode) throws ErrnoException;
+    public void chown(String path, int uid, int gid) throws ErrnoException;
     public void close(FileDescriptor fd) throws ErrnoException;
-    public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
+    public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
     public FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException;
     public FileDescriptor dup2(FileDescriptor oldFd, int newFd) throws ErrnoException;
     public String[] environ();
+    public void fchmod(FileDescriptor fd, int mode) throws ErrnoException;
+    public void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException;
     public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
     public int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException;
     public int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException;
@@ -67,6 +71,7 @@
     public int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException;
     public boolean isatty(FileDescriptor fd);
     public void kill(int pid, int signal) throws ErrnoException;
+    public void lchown(String path, int uid, int gid) throws ErrnoException;
     public void listen(FileDescriptor fd, int backlog) throws ErrnoException;
     public long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException;
     public StructStat lstat(String path) throws ErrnoException;
@@ -88,16 +93,17 @@
     public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException;
     public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException;
     public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException;
-    public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException;
-    public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException;
+    public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException;
+    public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException;
     public void remove(String path) throws ErrnoException;
     public void rename(String oldPath, String newPath) throws ErrnoException;
-    public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException;
-    public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException;
+    public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
+    public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
     public long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException;
     public void setegid(int egid) throws ErrnoException;
     public void seteuid(int euid) throws ErrnoException;
     public void setgid(int gid) throws ErrnoException;
+    public int setsid() throws ErrnoException;
     public void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
     public void setsockoptIfreq(FileDescriptor fd, int level, int option, String value) throws ErrnoException;
     public void setsockoptInt(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
@@ -114,6 +120,8 @@
     public String strerror(int errno);
     public void symlink(String oldPath, String newPath) throws ErrnoException;
     public long sysconf(int name);
+    public void tcdrain(FileDescriptor fd) throws ErrnoException;
+    public int umask(int mask);
     public StructUtsname uname();
     public int waitpid(int pid, MutableInt status, int options) throws ErrnoException;
     public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/OsConstants.java b/luni/src/main/java/libcore/io/OsConstants.java
index 68a165c..9f381f5 100644
--- a/luni/src/main/java/libcore/io/OsConstants.java
+++ b/luni/src/main/java/libcore/io/OsConstants.java
@@ -224,6 +224,7 @@
     public static final int O_CREAT = placeholder();
     public static final int O_EXCL = placeholder();
     public static final int O_NOCTTY = placeholder();
+    public static final int O_NOFOLLOW = placeholder();
     public static final int O_NONBLOCK = placeholder();
     public static final int O_RDONLY = placeholder();
     public static final int O_RDWR = placeholder();
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index 7bbf49f..ad01bcf 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -20,6 +20,7 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
+import java.net.SocketException;
 import java.nio.ByteBuffer;
 import java.nio.NioUtils;
 import libcore.util.MutableInt;
@@ -28,15 +29,18 @@
 public final class Posix implements Os {
     Posix() { }
 
-    public native FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException;
+    public native FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException;
     public native boolean access(String path, int mode) throws ErrnoException;
-    public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
+    public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
     public native void chmod(String path, int mode) throws ErrnoException;
+    public native void chown(String path, int uid, int gid) throws ErrnoException;
     public native void close(FileDescriptor fd) throws ErrnoException;
-    public native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException;
+    public native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
     public native FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException;
     public native FileDescriptor dup2(FileDescriptor oldFd, int newFd) throws ErrnoException;
     public native String[] environ();
+    public native void fchmod(FileDescriptor fd, int mode) throws ErrnoException;
+    public native void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException;
     public native int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
     public native int fcntlLong(FileDescriptor fd, int cmd, long arg) throws ErrnoException;
     public native int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException;
@@ -69,6 +73,7 @@
     public native int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException;
     public native boolean isatty(FileDescriptor fd);
     public native void kill(int pid, int signal) throws ErrnoException;
+    public native void lchown(String path, int uid, int gid) throws ErrnoException;
     public native void listen(FileDescriptor fd, int backlog) throws ErrnoException;
     public native long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException;
     public native StructStat lstat(String path) throws ErrnoException;
@@ -119,36 +124,37 @@
     }
     private native int readBytes(FileDescriptor fd, Object buffer, int offset, int byteCount) throws ErrnoException;
     public native int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException;
-    public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException {
+    public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
         if (buffer.isDirect()) {
             return recvfromBytes(fd, buffer, buffer.position(), buffer.remaining(), flags, srcAddress);
         } else {
             return recvfromBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining(), flags, srcAddress);
         }
     }
-    public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException {
+    public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException {
         // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
         return recvfromBytes(fd, bytes, byteOffset, byteCount, flags, srcAddress);
     }
-    private native int recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException;
+    private native int recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException;
     public native void remove(String path) throws ErrnoException;
     public native void rename(String oldPath, String newPath) throws ErrnoException;
     public native long sendfile(FileDescriptor outFd, FileDescriptor inFd, MutableLong inOffset, long byteCount) throws ErrnoException;
-    public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException {
+    public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
         if (buffer.isDirect()) {
             return sendtoBytes(fd, buffer, buffer.position(), buffer.remaining(), flags, inetAddress, port);
         } else {
             return sendtoBytes(fd, NioUtils.unsafeArray(buffer), NioUtils.unsafeArrayOffset(buffer) + buffer.position(), buffer.remaining(), flags, inetAddress, port);
         }
     }
-    public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException {
+    public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException {
         // This indirection isn't strictly necessary, but ensures that our public interface is type safe.
         return sendtoBytes(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
     }
-    private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException;
+    private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
     public native void setegid(int egid) throws ErrnoException;
     public native void seteuid(int euid) throws ErrnoException;
     public native void setgid(int gid) throws ErrnoException;
+    public native int setsid() throws ErrnoException;
     public native void setsockoptByte(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
     public native void setsockoptIfreq(FileDescriptor fd, int level, int option, String value) throws ErrnoException;
     public native void setsockoptInt(FileDescriptor fd, int level, int option, int value) throws ErrnoException;
@@ -164,6 +170,8 @@
     public native String strerror(int errno);
     public native void symlink(String oldPath, String newPath) throws ErrnoException;
     public native long sysconf(int name);
+    public native void tcdrain(FileDescriptor fd) throws ErrnoException;
+    public native int umask(int mask);
     public native StructUtsname uname();
     public native int waitpid(int pid, MutableInt status, int options) throws ErrnoException;
     public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {
diff --git a/luni/src/main/java/libcore/io/StrictLineReader.java b/luni/src/main/java/libcore/io/StrictLineReader.java
new file mode 100644
index 0000000..36556a0
--- /dev/null
+++ b/luni/src/main/java/libcore/io/StrictLineReader.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2012 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.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.Charsets;
+
+/**
+ * Buffers input from an {@link InputStream} for reading lines.
+ *
+ * This class is used for buffered reading of lines. For purposes of this class, a line ends with
+ * "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated line at
+ * end of input is invalid and will be ignored, the caller may use {@code hasUnterminatedLine()}
+ * to detect it after catching the {@code EOFException}.
+ *
+ * This class is intended for reading input that strictly consists of lines, such as line-based
+ * cache entries or cache journal. Unlike the {@link BufferedReader} which in conjunction with
+ * {@link InputStreamReader} provides similar functionality, this class uses different
+ * end-of-input reporting and a more restrictive definition of a line.
+ *
+ * This class supports only charsets that encode '\r' and '\n' as a single byte with value 13
+ * and 10, respectively, and the representation of no other character contains these values.
+ * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1.
+ * The default charset is US_ASCII.
+ */
+public class StrictLineReader implements Closeable {
+    private static final byte CR = (byte)'\r';
+    private static final byte LF = (byte)'\n';
+
+    private final InputStream in;
+    private final Charset charset;
+
+    /*
+     * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end
+     * and the data in the range [pos, end) is buffered for reading. At end of input, if there is
+     * an unterminated line, we set end == -1, otherwise end == pos. If the underlying
+     * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1.
+     */
+    private byte[] buf;
+    private int pos;
+    private int end;
+
+    /**
+     * Constructs a new {@code StrictLineReader} with the default capacity and charset.
+     *
+     * @param in the {@code InputStream} to read data from.
+     * @throws NullPointerException if {@code in} is null.
+     */
+    public StrictLineReader(InputStream in) {
+        this(in, 8192);
+    }
+
+    /**
+     * Constructs a new {@code LineReader} with the specified capacity and the default charset.
+     *
+     * @param in the {@code InputStream} to read data from.
+     * @param capacity the capacity of the buffer.
+     * @throws NullPointerException if {@code in} is null.
+     * @throws IllegalArgumentException for negative or zero {@code capacity}.
+     */
+    public StrictLineReader(InputStream in, int capacity) {
+        this(in, capacity, Charsets.US_ASCII);
+    }
+
+    /**
+     * Constructs a new {@code LineReader} with the specified charset and the default capacity.
+     *
+     * @param in the {@code InputStream} to read data from.
+     * @param charset the charset used to decode data.
+     *         Only US-ASCII, UTF-8 and ISO-8859-1 is supported.
+     * @throws NullPointerException if {@code in} or {@code charset} is null.
+     * @throws IllegalArgumentException if the specified charset is not supported.
+     */
+    public StrictLineReader(InputStream in, Charset charset) {
+        this(in, 8192, charset);
+    }
+
+    /**
+     * Constructs a new {@code LineReader} with the specified capacity and charset.
+     *
+     * @param in the {@code InputStream} to read data from.
+     * @param capacity the capacity of the buffer.
+     * @param charset the charset used to decode data.
+     *         Only US-ASCII, UTF-8 and ISO-8859-1 is supported.
+     * @throws NullPointerException if {@code in} or {@code charset} is null.
+     * @throws IllegalArgumentException if {@code capacity} is negative or zero
+     *         or the specified charset is not supported.
+     */
+    public StrictLineReader(InputStream in, int capacity, Charset charset) {
+        if (in == null) {
+            throw new NullPointerException("in == null");
+        } else if (charset == null) {
+            throw new NullPointerException("charset == null");
+        }
+        if (capacity < 0) {
+            throw new IllegalArgumentException("capacity <= 0");
+        }
+        if (!(charset.equals(Charsets.US_ASCII) || charset.equals(Charsets.UTF_8) ||
+                charset.equals(Charsets.ISO_8859_1))) {
+            throw new IllegalArgumentException("Unsupported encoding");
+        }
+
+        this.in = in;
+        this.charset = charset;
+        buf = new byte[capacity];
+    }
+
+    /**
+     * Closes the reader by closing the underlying {@code InputStream} and
+     * marking this reader as closed.
+     *
+     * @throws IOException for errors when closing the underlying {@code InputStream}.
+     */
+    @Override
+    public void close() throws IOException {
+        synchronized (in) {
+            if (buf != null) {
+                buf = null;
+                in.close();
+            }
+        }
+    }
+
+    /**
+     * Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"},
+     * this end of line marker is not included in the result.
+     *
+     * @return the next line from the input.
+     * @throws IOException for underlying {@code InputStream} errors.
+     * @throws EOFException for the end of source stream.
+     */
+    public String readLine() throws IOException {
+        synchronized (in) {
+            if (buf == null) {
+                throw new IOException("LineReader is closed");
+            }
+
+            // Read more data if we are at the end of the buffered data.
+            // Though it's an error to read after an exception, we will let {@code fillBuf()}
+            // throw again if that happens; thus we need to handle end == -1 as well as end == pos.
+            if (pos >= end) {
+                fillBuf();
+            }
+            // Try to find LF in the buffered data and return the line if successful.
+            for (int i = pos; i != end; ++i) {
+                if (buf[i] == LF) {
+                    int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;
+                    String res = new String(buf, pos, lineEnd - pos, charset);
+                    pos = i + 1;
+                    return res;
+                }
+            }
+
+            // Let's anticipate up to 80 characters on top of those already read.
+            ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) {
+                @Override
+                public String toString() {
+                    int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count;
+                    return new String(buf, 0, length, charset);
+                }
+            };
+
+            while (true) {
+                out.write(buf, pos, end - pos);
+                // Mark unterminated line in case fillBuf throws EOFException or IOException.
+                end = -1;
+                fillBuf();
+                // Try to find LF in the buffered data and return the line if successful.
+                for (int i = pos; i != end; ++i) {
+                    if (buf[i] == LF) {
+                        if (i != pos) {
+                            out.write(buf, pos, i - pos);
+                        }
+                        pos = i + 1;
+                        return out.toString();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Read an {@code int} from a line containing its decimal representation.
+     *
+     * @return the value of the {@code int} from the next line.
+     * @throws IOException for underlying {@code InputStream} errors or conversion error.
+     * @throws EOFException for the end of source stream.
+     */
+    public int readInt() throws IOException {
+        String intString = readLine();
+        try {
+            return Integer.parseInt(intString);
+        } catch (NumberFormatException e) {
+            throw new IOException("expected an int but was \"" + intString + "\"");
+        }
+    }
+
+    /**
+     * Check whether there was an unterminated line at end of input after the line reader reported
+     * end-of-input with EOFException. The value is meaningless in any other situation.
+     *
+     * @return true if there was an unterminated line at end of input.
+     */
+    public boolean hasUnterminatedLine() {
+        return end == -1;
+    }
+
+    /**
+     * Reads new input data into the buffer. Call only with pos == end or end == -1,
+     * depending on the desired outcome if the function throws.
+     *
+     * @throws IOException for underlying {@code InputStream} errors.
+     * @throws EOFException for the end of source stream.
+     */
+    private void fillBuf() throws IOException {
+        int result = in.read(buf, 0, buf.length);
+        if (result == -1) {
+            throw new EOFException();
+        }
+        pos = 0;
+        end = result;
+    }
+}
+
diff --git a/luni/src/main/java/libcore/net/MimeUtils.java b/luni/src/main/java/libcore/net/MimeUtils.java
index f8038f0..6ea0baf 100644
--- a/luni/src/main/java/libcore/net/MimeUtils.java
+++ b/luni/src/main/java/libcore/net/MimeUtils.java
@@ -350,6 +350,7 @@
         add("video/x-ms-wvx", "wvx");
         add("video/x-msvideo", "avi");
         add("video/x-sgi-movie", "movie");
+        add("video/x-webex", "wrf");
         add("x-conference/x-cooltalk", "ice");
         add("x-epoc/x-sisx-app", "sisx");
         applyOverrides();
diff --git a/luni/src/main/java/libcore/net/UriCodec.java b/luni/src/main/java/libcore/net/UriCodec.java
index bde922b..6624474 100644
--- a/luni/src/main/java/libcore/net/UriCodec.java
+++ b/luni/src/main/java/libcore/net/UriCodec.java
@@ -94,7 +94,7 @@
     private void appendEncoded(StringBuilder builder, String s, Charset charset,
             boolean isPartiallyEncoded) {
         if (s == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("s == null");
         }
 
         int escapeStart = -1;
diff --git a/luni/src/main/java/libcore/net/http/HttpEngine.java b/luni/src/main/java/libcore/net/http/HttpEngine.java
index 3e4b9d3..a370956 100644
--- a/luni/src/main/java/libcore/net/http/HttpEngine.java
+++ b/luni/src/main/java/libcore/net/http/HttpEngine.java
@@ -69,10 +69,10 @@
  * required, use {@link #automaticallyReleaseConnectionToPool()}.
  */
 public class HttpEngine {
-    private static final CacheResponse BAD_GATEWAY_RESPONSE = new CacheResponse() {
+    private static final CacheResponse GATEWAY_TIMEOUT_RESPONSE = new CacheResponse() {
         @Override public Map<String, List<String>> getHeaders() throws IOException {
             Map<String, List<String>> result = new HashMap<String, List<String>>();
-            result.put(null, Collections.singletonList("HTTP/1.1 502 Bad Gateway"));
+            result.put(null, Collections.singletonList("HTTP/1.1 504 Gateway Timeout"));
             return result;
         }
         @Override public InputStream getBody() throws IOException {
@@ -223,14 +223,15 @@
         /*
          * The raw response source may require the network, but the request
          * headers may forbid network use. In that case, dispose of the network
-         * response and use a BAD_GATEWAY response instead.
+         * response and use a GATEWAY_TIMEOUT response instead, as specified
+         * by http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4.
          */
         if (requestHeaders.isOnlyIfCached() && responseSource.requiresConnection()) {
             if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
                 IoUtils.closeQuietly(cachedResponseBody);
             }
             this.responseSource = ResponseSource.CACHE;
-            this.cacheResponse = BAD_GATEWAY_RESPONSE;
+            this.cacheResponse = GATEWAY_TIMEOUT_RESPONSE;
             RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(cacheResponse.getHeaders());
             setResponse(new ResponseHeaders(uri, rawResponseHeaders), cacheResponse.getBody());
         }
diff --git a/luni/src/main/java/libcore/net/http/HttpResponseCache.java b/luni/src/main/java/libcore/net/http/HttpResponseCache.java
index 7b95e1c..1a9dfd1 100644
--- a/luni/src/main/java/libcore/net/http/HttpResponseCache.java
+++ b/luni/src/main/java/libcore/net/http/HttpResponseCache.java
@@ -16,7 +16,6 @@
 
 package libcore.net.http;
 
-import java.io.BufferedInputStream;
 import java.io.BufferedWriter;
 import java.io.ByteArrayInputStream;
 import java.io.File;
@@ -53,7 +52,7 @@
 import libcore.io.Base64;
 import libcore.io.DiskLruCache;
 import libcore.io.IoUtils;
-import libcore.io.Streams;
+import libcore.io.StrictLineReader;
 
 /**
  * Cache responses in a directory on the file system. Most clients should use
@@ -100,7 +99,7 @@
             if (snapshot == null) {
                 return null;
             }
-            entry = new Entry(new BufferedInputStream(snapshot.getInputStream(ENTRY_METADATA)));
+            entry = new Entry(snapshot.getInputStream(ENTRY_METADATA));
         } catch (IOException e) {
             // Give up because the cache cannot be read.
             return null;
@@ -282,6 +281,13 @@
                     super.close();
                     editor.commit();
                 }
+
+                @Override
+                public void write(byte[] buffer, int offset, int length) throws IOException {
+                    // Since we don't override "write(int oneByte)", we can write directly to "out"
+                    // and avoid the inefficient implementation from the FilterOutputStream.
+                    out.write(buffer, offset, length);
+                }
             };
         }
 
@@ -362,29 +368,30 @@
          */
         public Entry(InputStream in) throws IOException {
             try {
-                uri = Streams.readAsciiLine(in);
-                requestMethod = Streams.readAsciiLine(in);
+                StrictLineReader reader = new StrictLineReader(in, Charsets.US_ASCII);
+                uri = reader.readLine();
+                requestMethod = reader.readLine();
                 varyHeaders = new RawHeaders();
-                int varyRequestHeaderLineCount = readInt(in);
+                int varyRequestHeaderLineCount = reader.readInt();
                 for (int i = 0; i < varyRequestHeaderLineCount; i++) {
-                    varyHeaders.addLine(Streams.readAsciiLine(in));
+                    varyHeaders.addLine(reader.readLine());
                 }
 
                 responseHeaders = new RawHeaders();
-                responseHeaders.setStatusLine(Streams.readAsciiLine(in));
-                int responseHeaderLineCount = readInt(in);
+                responseHeaders.setStatusLine(reader.readLine());
+                int responseHeaderLineCount = reader.readInt();
                 for (int i = 0; i < responseHeaderLineCount; i++) {
-                    responseHeaders.addLine(Streams.readAsciiLine(in));
+                    responseHeaders.addLine(reader.readLine());
                 }
 
                 if (isHttps()) {
-                    String blank = Streams.readAsciiLine(in);
+                    String blank = reader.readLine();
                     if (!blank.isEmpty()) {
                         throw new IOException("expected \"\" but was \"" + blank + "\"");
                     }
-                    cipherSuite = Streams.readAsciiLine(in);
-                    peerCertificates = readCertArray(in);
-                    localCertificates = readCertArray(in);
+                    cipherSuite = reader.readLine();
+                    peerCertificates = readCertArray(reader);
+                    localCertificates = readCertArray(reader);
                 } else {
                     cipherSuite = null;
                     peerCertificates = null;
@@ -419,7 +426,7 @@
         }
 
         public void writeTo(DiskLruCache.Editor editor) throws IOException {
-            OutputStream out = editor.newOutputStream(0);
+            OutputStream out = editor.newOutputStream(ENTRY_METADATA);
             Writer writer = new BufferedWriter(new OutputStreamWriter(out, Charsets.UTF_8));
 
             writer.write(uri + '\n');
@@ -450,17 +457,8 @@
             return uri.startsWith("https://");
         }
 
-        private int readInt(InputStream in) throws IOException {
-            String intString = Streams.readAsciiLine(in);
-            try {
-                return Integer.parseInt(intString);
-            } catch (NumberFormatException e) {
-                throw new IOException("expected an int but was \"" + intString + "\"");
-            }
-        }
-
-        private Certificate[] readCertArray(InputStream in) throws IOException {
-            int length = readInt(in);
+        private Certificate[] readCertArray(StrictLineReader reader) throws IOException {
+            int length = reader.readInt();
             if (length == -1) {
                 return null;
             }
@@ -468,7 +466,7 @@
                 CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                 Certificate[] result = new Certificate[length];
                 for (int i = 0; i < result.length; i++) {
-                    String line = Streams.readAsciiLine(in);
+                    String line = reader.readLine();
                     byte[] bytes = Base64.decode(line.getBytes(Charsets.US_ASCII));
                     result[i] = certificateFactory.generateCertificate(
                             new ByteArrayInputStream(bytes));
diff --git a/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java b/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java
index a59df55..260a9ad 100644
--- a/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java
+++ b/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java
@@ -36,6 +36,7 @@
 import java.util.List;
 import java.util.Map;
 import libcore.io.Base64;
+import libcore.io.IoUtils;
 
 /**
  * This implementation uses HttpEngine to send requests and receive responses.
@@ -87,6 +88,14 @@
     @Override public final void disconnect() {
         // Calling disconnect() before a connection exists should have no effect.
         if (httpEngine != null) {
+            // We close the response body here instead of in
+            // HttpEngine.release because that is called when input
+            // has been completely read from the underlying socket.
+            // However the response body can be a GZIPInputStream that
+            // still has unread data.
+            if (httpEngine.hasResponse()) {
+                IoUtils.closeQuietly(httpEngine.getResponseBody());
+            }
             httpEngine.release(false);
         }
     }
diff --git a/luni/src/main/java/libcore/util/BasicLruCache.java b/luni/src/main/java/libcore/util/BasicLruCache.java
index 13ab3db..75e4a75 100644
--- a/luni/src/main/java/libcore/util/BasicLruCache.java
+++ b/luni/src/main/java/libcore/util/BasicLruCache.java
@@ -43,7 +43,7 @@
      */
     public synchronized final V get(K key) {
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
 
         V result = map.get(key);
@@ -68,8 +68,10 @@
      *     no longer cached, it has not been passed to {@link #entryEvicted}.
      */
     public synchronized final V put(K key, V value) {
-        if (key == null || value == null) {
-            throw new NullPointerException();
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        } else if (value == null) {
+            throw new NullPointerException("value == null");
         }
 
         V previous = map.put(key, value);
diff --git a/luni/src/main/java/libcore/util/Objects.java b/luni/src/main/java/libcore/util/Objects.java
index 7817316..573b973 100644
--- a/luni/src/main/java/libcore/util/Objects.java
+++ b/luni/src/main/java/libcore/util/Objects.java
@@ -16,6 +16,10 @@
 
 package libcore.util;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+
 public final class Objects {
     private Objects() {}
 
@@ -29,4 +33,64 @@
     public static int hashCode(Object o) {
         return (o == null) ? 0 : o.hashCode();
     }
+
+    /**
+     * Returns a string reporting the value of each declared field, via reflection.
+     * Static and transient fields are automatically skipped. Produces output like
+     * "SimpleClassName[integer=1234,string="hello",character='c',intArray=[1,2,3]]".
+     */
+    public static String toString(Object o) {
+        Class<?> c = o.getClass();
+        StringBuilder sb = new StringBuilder();
+        sb.append(c.getSimpleName()).append('[');
+        int i = 0;
+        for (Field f : c.getDeclaredFields()) {
+            if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0) {
+                continue;
+            }
+            f.setAccessible(true);
+            try {
+                Object value = f.get(o);
+
+                if (i++ > 0) {
+                    sb.append(',');
+                }
+
+                sb.append(f.getName());
+                sb.append('=');
+
+                if (value.getClass().isArray()) {
+                    if (value.getClass() == boolean[].class) {
+                        sb.append(Arrays.toString((boolean[]) value));
+                    } else if (value.getClass() == byte[].class) {
+                        sb.append(Arrays.toString((byte[]) value));
+                    } else if (value.getClass() == char[].class) {
+                        sb.append(Arrays.toString((char[]) value));
+                    } else if (value.getClass() == double[].class) {
+                        sb.append(Arrays.toString((double[]) value));
+                    } else if (value.getClass() == float[].class) {
+                        sb.append(Arrays.toString((float[]) value));
+                    } else if (value.getClass() == int[].class) {
+                        sb.append(Arrays.toString((int[]) value));
+                    } else if (value.getClass() == long[].class) {
+                        sb.append(Arrays.toString((long[]) value));
+                    } else if (value.getClass() == short[].class) {
+                        sb.append(Arrays.toString((short[]) value));
+                    } else {
+                        sb.append(Arrays.toString((Object[]) value));
+                    }
+                } else if (value.getClass() == Character.class) {
+                    sb.append('\'').append(value).append('\'');
+                } else if (value.getClass() == String.class) {
+                    sb.append('"').append(value).append('"');
+                } else {
+                    sb.append(value);
+                }
+            } catch (IllegalAccessException unexpected) {
+                throw new AssertionError(unexpected);
+            }
+        }
+        sb.append("]");
+        return sb.toString();
+    }
 }
diff --git a/luni/src/main/java/libcore/util/ZoneInfo.java b/luni/src/main/java/libcore/util/ZoneInfo.java
index 5a8caf2..ac48b23 100644
--- a/luni/src/main/java/libcore/util/ZoneInfo.java
+++ b/luni/src/main/java/libcore/util/ZoneInfo.java
@@ -51,29 +51,46 @@
     private final byte[] mTypes;
     private final byte[] mIsDsts;
     private final boolean mUseDst;
+    private final int mDstSavings; // Implements TimeZone.getDSTSavings.
 
-    ZoneInfo(String name, int[] transitions, byte[] type, int[] gmtOffsets, byte[] isDsts) {
+    ZoneInfo(String name, int[] transitions, byte[] types, int[] gmtOffsets, byte[] isDsts) {
         mTransitions = transitions;
-        mTypes = type;
+        mTypes = types;
         mIsDsts = isDsts;
         setID(name);
 
-        // Use the latest non-daylight offset (if any) as the raw offset.
-        int lastStd;
-        for (lastStd = mTransitions.length - 1; lastStd >= 0; lastStd--) {
-            if (mIsDsts[mTypes[lastStd] & 0xff] == 0) {
-                break;
+        // Find the latest daylight and standard offsets (if any).
+        int lastStd = 0;
+        boolean haveStd = false;
+        int lastDst = 0;
+        boolean haveDst = false;
+        for (int i = mTransitions.length - 1; (!haveStd || !haveDst) && i >= 0; --i) {
+            int type = mTypes[i] & 0xff;
+            if (!haveStd && mIsDsts[type] == 0) {
+                haveStd = true;
+                lastStd = i;
+            }
+            if (!haveDst && mIsDsts[type] != 0) {
+                haveDst = true;
+                lastDst = i;
             }
         }
-        if (lastStd < 0) {
-            lastStd = 0;
-        }
+
+        // Use the latest non-daylight offset (if any) as the raw offset.
         if (lastStd >= mTypes.length) {
             mRawOffset = gmtOffsets[0];
         } else {
             mRawOffset = gmtOffsets[mTypes[lastStd] & 0xff];
         }
 
+        // Use the latest transition's pair of offsets to compute the DST savings.
+        // This isn't generally useful, but it's exposed by TimeZone.getDSTSavings.
+        if (lastDst >= mTypes.length) {
+            mDstSavings = 0;
+        } else {
+            mDstSavings = Math.abs(gmtOffsets[mTypes[lastStd] & 0xff] - gmtOffsets[mTypes[lastDst] & 0xff]) * 1000;
+        }
+
         // Cache the oldest known raw offset, in case we're asked about times that predate our
         // transition data.
         int firstStd = -1;
@@ -111,6 +128,7 @@
         }
         mUseDst = usesDst;
 
+        // tzdata uses seconds, but Java uses milliseconds.
         mRawOffset *= 1000;
         mEarliestRawOffset = earliestRawOffset * 1000;
     }
@@ -185,6 +203,10 @@
         mRawOffset = off;
     }
 
+    @Override public int getDSTSavings() {
+        return mUseDst ? mDstSavings: 0;
+    }
+
     @Override public boolean useDaylightTime() {
         return mUseDst;
     }
@@ -235,7 +257,7 @@
         StringBuilder sb = new StringBuilder();
         // First the basics...
         sb.append(getClass().getName() + "[" + getID() + ",mRawOffset=" + mRawOffset +
-                ",mUseDst=" + mUseDst + "]");
+                ",mUseDst=" + mUseDst + ",mDstSavings=" + mDstSavings + "]");
         // ...followed by a zdump(1)-like description of all our transition data.
         sb.append("\n");
         Formatter f = new Formatter(sb);
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index 69b6784..cc7cc4f 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -180,7 +180,7 @@
         }
     }
 
-    private static TimeZone makeTimeZone(String id) throws IOException {
+    public static TimeZone makeTimeZone(String id) throws IOException {
         // Work out where in the big data file this time zone is.
         int index = Arrays.binarySearch(ids, id);
         if (index < 0) {
@@ -259,17 +259,6 @@
         }
     }
 
-    public static TimeZone getTimeZone(String id) {
-        if (id == null) {
-            return null;
-        }
-        try {
-            return makeTimeZone(id);
-        } catch (IOException ignored) {
-            return null;
-        }
-    }
-
     public static String getVersion() {
         return VERSION;
     }
diff --git a/luni/src/main/java/org/apache/harmony/crypto/internal/NullCipherSpi.java b/luni/src/main/java/org/apache/harmony/crypto/internal/NullCipherSpi.java
index 270f63b..151b403 100644
--- a/luni/src/main/java/org/apache/harmony/crypto/internal/NullCipherSpi.java
+++ b/luni/src/main/java/org/apache/harmony/crypto/internal/NullCipherSpi.java
@@ -115,8 +115,10 @@
     @Override
     public int engineUpdate(ByteBuffer input, ByteBuffer output)
             throws ShortBufferException {
-        if (input == null || output == null) {
-            throw new NullPointerException();
+        if (input == null) {
+            throw new NullPointerException("input == null");
+        } else if (output == null) {
+            throw new NullPointerException("output == null");
         }
         int result = input.limit() - input.position();
         try {
diff --git a/luni/src/main/java/org/apache/harmony/luni/util/TwoKeyHashMap.java b/luni/src/main/java/org/apache/harmony/luni/util/TwoKeyHashMap.java
deleted file mode 100644
index 35e6c62..0000000
--- a/luni/src/main/java/org/apache/harmony/luni/util/TwoKeyHashMap.java
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You 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 org.apache.harmony.luni.util;
-
-import java.util.AbstractCollection;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-/**
- *
- * Reductive hash with two keys
- *
- */
-public class TwoKeyHashMap<E, K, V> extends AbstractMap<String, V> {
-
-    static final float DEFAULT_LOAD_FACTOR = 0.75f;
-    static final int DEFAULT_INITIAL_SIZE = 16;
-
-    private Set<Map.Entry<String, V>> entrySet;
-    private Collection<V> values;
-    private int size;
-    private int arrSize;
-    private int modCount;
-
-    private Entry<E, K, V>[] arr;
-
-    private float loadFactor;
-    int threshold = 0;
-
-    /**
-     * Constructs an empty HashMap
-     */
-    public TwoKeyHashMap() {
-        this(DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR);
-    }
-
-    /**
-     * Constructs an empty HashMap
-     *
-     * @param initialCapacity
-     */
-    public TwoKeyHashMap(int initialCapacity) {
-        this(initialCapacity, DEFAULT_LOAD_FACTOR);
-    }
-
-    /**
-     * Constructs an empty HashMap
-     *
-     * @param initialCapacity
-     * @param initialLoadFactor
-     */
-    @SuppressWarnings("unchecked")
-    public TwoKeyHashMap(int initialCapacity, float initialLoadFactor) {
-        if (initialCapacity < 0) {
-            throw new IllegalArgumentException("initialCapacity should be >= 0");
-        }
-        if (initialLoadFactor <= 0) {
-            throw new IllegalArgumentException(
-                    "initialLoadFactor should be > 0");
-        }
-        loadFactor = initialLoadFactor;
-        if (initialCapacity == Integer.MAX_VALUE) {
-            initialCapacity--;
-        }
-        arrSize = initialCapacity > 0 ? initialCapacity : 1;
-        threshold = (int) (arrSize * loadFactor);
-        arr = new Entry[arrSize + 1];
-    }
-
-    /**
-     * Returns a collection view of the values
-     */
-    public Collection<V> values() {
-        if (values == null) {
-            values = new ValuesCollectionImpl();
-        }
-        return values;
-    }
-
-    /**
-     * Returns a collection view of the mappings
-     */
-    public Set<Map.Entry<String, V>> entrySet() {
-        if (entrySet == null) {
-            entrySet = new EntrySetImpl();
-        }
-        return entrySet;
-    }
-
-    /**
-     * Clears the map
-     */
-    public void clear() {
-        modCount++;
-        size = 0;
-        Arrays.fill(arr, 0, arr.length, null);
-    }
-
-    /**
-     * Removes the mapping for the keys
-     *
-     * @param key1
-     * @param key2
-     * @return
-     */
-    public V remove(Object key1, Object key2) {
-        Entry<E, K, V> e = removeEntry(key1, key2);
-        return (e != null) ? e.value : null;
-    }
-
-    /**
-     * Associates the specified value with the specified keys in this map
-     *
-     * @param key1
-     * @param key2
-     * @param value
-     * @return
-     */
-    public V put(E key1, K key2, V value) {
-        if (key1 == null && key2 == null) {
-            int index = arrSize;
-            if (arr[index] == null) {
-                arr[index] = createEntry(0, null, null, value, null);
-                size++;
-                modCount++;
-                return null;
-            } else {
-                V oldValue = arr[index].value;
-                arr[index].value = value;
-                return oldValue;
-            }
-        }
-
-        int hash = key1.hashCode() + key2.hashCode();
-        int index = (hash & 0x7fffffff) % arrSize;
-        Entry<E, K, V> e = arr[index];
-
-        while (e != null) {
-            if (hash == e.hash && key1.equals(e.getKey1())
-                    && key2.equals(e.getKey2())) {
-                V oldValue = e.value;
-                e.value = value;
-                return oldValue;
-            }
-            e = e.next;
-        }
-
-        arr[index] = createEntry(hash, key1, key2, value, arr[index]);
-        size++;
-        modCount++;
-
-        if (size > threshold) {
-            rehash();
-        }
-        return null;
-    }
-
-    /**
-     * Rehash the map
-     *
-     */
-    @SuppressWarnings("unchecked")
-    void rehash() {
-        int newArrSize = (arrSize + 1) * 2 + 1;
-        if (newArrSize < 0) {
-            newArrSize = Integer.MAX_VALUE - 1;
-        }
-        Entry<E, K, V>[] newArr = new Entry[newArrSize + 1];
-
-        for (int i = 0; i < arr.length - 1; i++) {
-            Entry<E, K, V> entry = arr[i];
-            while (entry != null) {
-                Entry<E, K, V> next = entry.next;
-
-                int newIndex = (entry.hash & 0x7fffffff) % newArrSize;
-                entry.next = newArr[newIndex];
-                newArr[newIndex] = entry;
-
-                entry = next;
-            }
-        }
-        newArr[newArrSize] = arr[arrSize]; // move null entry
-        arrSize = newArrSize;
-
-        // The maximum array size is reached, increased loadFactor
-        // will keep array from further growing
-        if (arrSize == Integer.MAX_VALUE) {
-            loadFactor *= 10;
-        }
-        threshold = (int) (arrSize * loadFactor);
-        arr = newArr;
-    }
-
-    /**
-     * Returns true if this map contains a mapping for {@code key1} and {@code key2}.
-     */
-    public boolean containsKey(Object key1, Object key2) {
-        return findEntry(key1, key2) != null;
-    }
-
-    /**
-     * Return the value by keys
-     *
-     * @param key1
-     * @param key2
-     * @return
-     */
-    public V get(Object key1, Object key2) {
-        Entry<E, K, V> e = findEntry(key1, key2);
-        if (e != null) {
-            return e.value;
-        }
-        return null;
-    }
-
-    /**
-     * Returns true if this map contains no key-value mappings
-     */
-    public boolean isEmpty() {
-        return size == 0;
-    }
-
-    /**
-     * Returns the number of mappings
-     */
-    public int size() {
-        return size;
-    }
-
-    /**
-     * Creates new entry
-     *
-     * @param hashCode
-     * @param key1
-     * @param key2
-     * @param value
-     * @param next
-     * @return
-     */
-    Entry<E, K, V> createEntry(int hashCode, E key1, K key2, V value,
-            Entry<E, K, V> next) {
-        return new Entry<E, K, V>(hashCode, key1, key2, value, next);
-    }
-
-    /**
-     * Creates entries iterator
-     *
-     * @return
-     */
-    Iterator<Map.Entry<String, V>> createEntrySetIterator() {
-        return new EntryIteratorImpl();
-    }
-
-    /**
-     * Creates values iterator
-     *
-     * @return
-     */
-    Iterator<V> createValueCollectionIterator() {
-        return new ValueIteratorImpl();
-    }
-
-    /**
-     * Entry implementation for the TwoKeyHashMap class
-     *
-     */
-    public static class Entry<E, K, V> implements Map.Entry<String, V> {
-        int hash;
-        E key1;
-        K key2;
-        V value;
-        Entry<E, K, V> next;
-
-        public Entry(int hash, E key1, K key2, V value, Entry<E, K, V> next) {
-            this.hash = hash;
-            this.key1 = key1;
-            this.key2 = key2;
-            this.value = value;
-            this.next = next;
-        }
-
-        public String getKey() {
-            return key1.toString() + key2.toString();
-        }
-
-        public E getKey1() {
-            return key1;
-        }
-
-        public K getKey2() {
-            return key2;
-        }
-
-        public V getValue() {
-            return value;
-        }
-
-        public V setValue(V value) {
-            V oldValue = this.value;
-            this.value = value;
-            return oldValue;
-        }
-
-        public boolean equals(Object obj) {
-            if (!(obj instanceof Entry)) {
-                return false;
-            }
-
-            Entry<?, ?, ?> e = (Entry<?, ?, ?>) obj;
-            Object getKey1 = e.getKey1();
-            Object getKey2 = e.getKey2();
-            Object getValue = e.getValue();
-            if ((key1 == null && getKey1 != null)
-                    || (key2 == null && getKey2 != null)
-                    || (value == null && getValue != null)
-                    || !key1.equals(e.getKey1()) || !key2.equals(e.getKey2())
-                    || !value.equals(getValue)) {
-                return false;
-            }
-            return true;
-        }
-
-        public int hashCode() {
-            int hash1 = (key1 == null ? 0 : key1.hashCode());
-            int hash2 = (key2 == null ? 0 : key2.hashCode());
-            return (hash1 + hash2) ^ (value == null ? 0 : value.hashCode());
-        }
-
-    }
-
-    class EntrySetImpl extends AbstractSet<Map.Entry<String, V>> {
-        public int size() {
-            return size;
-        }
-
-        public void clear() {
-            TwoKeyHashMap.this.clear();
-        }
-
-        public boolean isEmpty() {
-            return size == 0;
-        }
-
-        public boolean contains(Object obj) {
-            if (!(obj instanceof Entry)) {
-                return false;
-            }
-
-            Entry<?, ?, ?> entry = (Entry<?, ?, ?>) obj;
-            Entry<E, K, V> entry2 = findEntry(entry.getKey1(), entry.getKey2());
-            if (entry2 == null) {
-                return false;
-            }
-            Object value = entry.getValue();
-            Object value2 = entry2.getValue();
-            return value == null ? value2 == null : value.equals(value2);
-        }
-
-        public boolean remove(Object obj) {
-            if (!(obj instanceof Entry)) {
-                return false;
-            }
-            return removeEntry(((Entry) obj).getKey1(), ((Entry) obj).getKey2()) != null;
-        }
-
-        public Iterator<Map.Entry<String, V>> iterator() {
-            return createEntrySetIterator();
-        }
-    }
-
-    // Iterates Entries inside the Map
-    class EntryIteratorImpl implements Iterator<Map.Entry<String, V>> {
-        private int startModCount;
-        private boolean found;
-        private int curr = -1;
-        private int returned_index = -1;
-        private Entry<E, K, V> curr_entry;
-        private Entry<E, K, V> returned_entry;
-
-        EntryIteratorImpl() {
-            startModCount = modCount;
-        }
-
-        public boolean hasNext() {
-            if (found) {
-                return true;
-            }
-            if (curr_entry != null) {
-                curr_entry = curr_entry.next;
-            }
-            if (curr_entry == null) {
-                for (curr++; curr < arr.length && arr[curr] == null; curr++) {
-                }
-
-                if (curr < arr.length) {
-                    curr_entry = arr[curr];
-                }
-            }
-            return found = (curr_entry != null);
-        }
-
-        public Map.Entry<String, V> next() {
-            if (modCount != startModCount) {
-                throw new ConcurrentModificationException();
-            }
-            if (!hasNext()) {
-                throw new NoSuchElementException();
-            }
-
-            found = false;
-            returned_index = curr;
-            returned_entry = curr_entry;
-            return (Map.Entry<String, V>) curr_entry;
-        }
-
-        public void remove() {
-            if (returned_index == -1) {
-                throw new IllegalStateException();
-            }
-
-            if (modCount != startModCount) {
-                throw new ConcurrentModificationException();
-            }
-
-            Entry<E, K, V> p = null;
-            Entry<E, K, V> e = arr[returned_index];
-            while (e != returned_entry) {
-                p = e;
-                e = e.next;
-            }
-            if (p != null) {
-                p.next = returned_entry.next;
-            } else {
-                arr[returned_index] = returned_entry.next;
-            }
-            size--;
-            modCount++;
-            startModCount++;
-            returned_index = -1;
-        }
-    }
-
-    private final Entry<E, K, V> findEntry(Object key1, Object key2) {
-        if (key1 == null && key2 == null) {
-            return arr[arrSize];
-        }
-
-        int hash = key1.hashCode() + key2.hashCode();
-        int index = (hash & 0x7fffffff) % arrSize;
-        Entry<E, K, V> e = arr[index];
-
-        while (e != null) {
-            if (hash == e.hash && key1.equals(e.getKey1())
-                    && key2.equals(e.getKey2())) {
-                return e;
-            }
-            e = e.next;
-        }
-        return null;
-    }
-
-    // Removes entry
-    private final Entry<E, K, V> removeEntry(Object key1, Object key2) {
-        if (key1 == null && key2 == null) {
-            int index = arrSize;
-            if (arr[index] != null) {
-                Entry<E, K, V> ret = arr[index];
-                arr[index] = null;
-                size--;
-                modCount++;
-                return ret;
-            }
-            return null;
-        }
-
-        int hash = key1.hashCode() + key2.hashCode();
-        int index = (hash & 0x7fffffff) % arrSize;
-
-        Entry<E, K, V> e = arr[index];
-        Entry<E, K, V> prev = e;
-        while (e != null) {
-            if (hash == e.hash && key1.equals(e.getKey1())
-                    && key2.equals(e.getKey2())) {
-                if (prev == e) {
-                    arr[index] = e.next;
-                } else {
-                    prev.next = e.next;
-                }
-                size--;
-                modCount++;
-                return e;
-            }
-
-            prev = e;
-            e = e.next;
-        }
-        return null;
-    }
-
-    /**
-     * An instance is returned by the values() call.
-     */
-    class ValuesCollectionImpl extends AbstractCollection<V> {
-        public int size() {
-            return size;
-        }
-
-        public void clear() {
-            TwoKeyHashMap.this.clear();
-        }
-
-        public boolean isEmpty() {
-            return size == 0;
-        }
-
-        public Iterator<V> iterator() {
-            return createValueCollectionIterator();
-        }
-
-        public boolean contains(Object obj) {
-            return containsValue(obj);
-        }
-    }
-
-    class ValueIteratorImpl implements Iterator<V> {
-        private EntryIteratorImpl itr;
-
-        ValueIteratorImpl() {
-            this.itr = new EntryIteratorImpl();
-        }
-
-        public V next() {
-            return itr.next().getValue();
-        }
-
-        public void remove() {
-            itr.remove();
-        }
-
-        public boolean hasNext() {
-            return itr.hasNext();
-        }
-    }
-}
diff --git a/luni/src/main/java/org/apache/harmony/security/SystemScope.java b/luni/src/main/java/org/apache/harmony/security/SystemScope.java
index 89cf56b..bf4f849 100644
--- a/luni/src/main/java/org/apache/harmony/security/SystemScope.java
+++ b/luni/src/main/java/org/apache/harmony/security/SystemScope.java
@@ -79,7 +79,7 @@
      */
     public synchronized Identity getIdentity(String name) {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
         return (Identity) names.get(name);
     }
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
index 8a67ac2..f1dd43c 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
@@ -93,15 +93,15 @@
         /** used to test for cache hit */
         private final String algorithm;
         /** used to test for cache validity */
-        private final int refreshNumber;
+        private final int cacheVersion;
         /** cached result */
         private final Provider.Service service;
 
         private ServiceCacheEntry(String algorithm,
-                                  int refreshNumber,
+                                  int cacheVersion,
                                   Provider.Service service) {
             this.algorithm = algorithm;
-            this.refreshNumber = refreshNumber;
+            this.cacheVersion = cacheVersion;
             this.service = service;
         }
     }
@@ -134,12 +134,12 @@
         if (algorithm == null) {
             throw new NoSuchAlgorithmException("Null algorithm name");
         }
-        Services.refresh();
+        int newCacheVersion = Services.getCacheVersion();
         Provider.Service service;
         ServiceCacheEntry cacheEntry = this.serviceCache;
         if (cacheEntry != null
                 && cacheEntry.algorithm.equalsIgnoreCase(algorithm)
-                && Services.refreshNumber == cacheEntry.refreshNumber) {
+                && newCacheVersion == cacheEntry.cacheVersion) {
             service = cacheEntry.service;
         } else {
             if (Services.isEmpty()) {
@@ -150,7 +150,7 @@
             if (service == null) {
                 throw notFound(serviceName, algorithm);
             }
-            this.serviceCache = new ServiceCacheEntry(algorithm, Services.refreshNumber, service);
+            this.serviceCache = new ServiceCacheEntry(algorithm, newCacheVersion, service);
         }
         return new SpiAndProvider(service.newInstance(param), service.getProvider());
     }
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
index d97e0f4..4fe0d44 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
@@ -15,11 +15,6 @@
  *  limitations under the License.
  */
 
-/**
-* @author Boris V. Kuznetsov
-* @version $Revision$
-*/
-
 package org.apache.harmony.security.fortress;
 
 import java.security.Provider;
@@ -34,87 +29,83 @@
 /**
  * This class contains information about all registered providers and preferred
  * implementations for all "serviceName.algName".
- *
  */
-
 public class Services {
 
-    // The HashMap that contains information about preferred implementations for
-    // all serviceName.algName in the registered providers.
-    // Set the initial size to 600 so we don't grow to 1024 by default because
-    // initialization adds a few entries more than the growth threshold.
+    /**
+     * The HashMap that contains information about preferred implementations for
+     * all serviceName.algName in the registered providers.
+     * Set the initial size to 600 so we don't grow to 1024 by default because
+     * initialization adds a few entries more than the growth threshold.
+     */
     private static final Map<String, Provider.Service> services
             = new HashMap<String, Provider.Service>(600);
-    // Save default SecureRandom service as well.
-    // Avoids similar provider/services iteration in SecureRandom constructor
-    private static Provider.Service secureRandom;
-
-    // Need refresh flag
-    private static boolean needRefresh; // = false;
 
     /**
-     * Refresh number
+     * Save default SecureRandom service as well.
+     * Avoids similar provider/services iteration in SecureRandom constructor.
      */
-    static int refreshNumber = 1;
+    private static Provider.Service cachedSecureRandomService;
 
-    // Registered providers
+    /**
+     * Need refresh flag.
+     */
+    private static boolean needRefresh;
+
+    /**
+     * The cacheVersion is changed on every update of service
+     * information. It is used by external callers to validate their
+     * own caches of Service information.
+     */
+    private static int cacheVersion = 1;
+
+    /**
+     * Registered providers.
+     */
     private static final List<Provider> providers = new ArrayList<Provider>(20);
 
-    // Hash for quick provider access by name
+    /**
+     * Hash for quick provider access by name.
+     */
     private static final Map<String, Provider> providersNames = new HashMap<String, Provider>(20);
     static {
-        loadProviders();
-    }
-
-    // Load statically registered providers and init Services Info
-    private static void loadProviders() {
         String providerClassName = null;
         int i = 1;
         ClassLoader cl = ClassLoader.getSystemClassLoader();
-        Provider p;
 
-        while ((providerClassName = Security.getProperty("security.provider."
-                + i++)) != null) {
+        while ((providerClassName = Security.getProperty("security.provider." + i++)) != null) {
             try {
-                p = (Provider) Class
-                        .forName(providerClassName.trim(), true, cl)
-                        .newInstance();
+                Class providerClass = Class.forName(providerClassName.trim(), true, cl);
+                Provider p = (Provider) providerClass.newInstance();
                 providers.add(p);
                 providersNames.put(p.getName(), p);
                 initServiceInfo(p);
-            } catch (ClassNotFoundException e) { // ignore Exceptions
-            } catch (IllegalAccessException e) {
-            } catch (InstantiationException e) {
+            } catch (ClassNotFoundException ignored) {
+            } catch (IllegalAccessException ignored) {
+            } catch (InstantiationException ignored) {
             }
         }
         Engine.door.renumProviders();
     }
 
     /**
-     * Returns registered providers
-     *
-     * @return
+     * Returns a copy of the registered providers as an array.
      */
-    public static Provider[] getProviders() {
+    public static synchronized Provider[] getProviders() {
         return providers.toArray(new Provider[providers.size()]);
     }
 
     /**
-     * Returns registered providers as List
-     *
-     * @return
+     * Returns a copy of the registered providers as a list.
      */
-    public static List<Provider> getProvidersList() {
+    public static synchronized List<Provider> getProvidersList() {
         return new ArrayList<Provider>(providers);
     }
 
     /**
-     * Returns the provider with the specified name
-     *
-     * @param name
-     * @return
+     * Returns the provider with the specified name.
      */
-    public static Provider getProvider(String name) {
+    public static synchronized Provider getProvider(String name) {
         if (name == null) {
             return null;
         }
@@ -122,13 +113,9 @@
     }
 
     /**
-     * Inserts a provider at a specified position
-     *
-     * @param provider
-     * @param position
-     * @return
+     * Inserts a provider at a specified 1-based position.
      */
-    public static int insertProviderAt(Provider provider, int position) {
+    public static synchronized int insertProviderAt(Provider provider, int position) {
         int size = providers.size();
         if ((position < 1) || (position > size)) {
             position = size + 1;
@@ -140,98 +127,91 @@
     }
 
     /**
-     * Removes the provider
-     *
-     * @param providerNumber
+     * Removes the provider at the specified 1-based position.
      */
-    public static void removeProvider(int providerNumber) {
+    public static synchronized void removeProvider(int providerNumber) {
         Provider p = providers.remove(providerNumber - 1);
         providersNames.remove(p.getName());
         setNeedRefresh();
     }
 
     /**
-     *
      * Adds information about provider services into HashMap.
-     *
-     * @param p
      */
-    public static void initServiceInfo(Provider p) {
-        for (Provider.Service serv : p.getServices()) {
-            String type = serv.getType();
-            if (secureRandom == null && type.equals("SecureRandom")) {
-                secureRandom = serv;
+    public static synchronized void initServiceInfo(Provider p) {
+        for (Provider.Service service : p.getServices()) {
+            String type = service.getType();
+            if (cachedSecureRandomService == null && type.equals("SecureRandom")) {
+                cachedSecureRandomService = service;
             }
-            String key = type + "." + serv.getAlgorithm().toUpperCase(Locale.US);
+            String key = type + "." + service.getAlgorithm().toUpperCase(Locale.US);
             if (!services.containsKey(key)) {
-                services.put(key, serv);
+                services.put(key, service);
             }
-            for (String alias : Engine.door.getAliases(serv)) {
+            for (String alias : Engine.door.getAliases(service)) {
                 key = type + "." + alias.toUpperCase(Locale.US);
                 if (!services.containsKey(key)) {
-                    services.put(key, serv);
+                    services.put(key, service);
                 }
             }
         }
     }
 
     /**
-     *
-     * Updates services hashtable for all registered providers
-     *
+     * Returns true if services contain any provider information.
      */
-    public static void updateServiceInfo() {
-        services.clear();
-        secureRandom = null;
-        for (Provider p : providers) {
-            initServiceInfo(p);
-        }
-        needRefresh = false;
-    }
-
-    /**
-     * Returns true if services contain any provider information
-     * @return
-     */
-    public static boolean isEmpty() {
+    public static synchronized boolean isEmpty() {
         return services.isEmpty();
     }
 
     /**
-     * Returns service description.
-     * Call refresh() before.
+     * Looks up the requested service by type and algorithm. The
+     * service key should be provided in the same format used when
+     * registering a service with a provider, for example,
+     * "KeyFactory.RSA".
      *
-     * @param key in the format TYPE.ALGORITHM
-     * @return
+     * Callers can cache the returned service information but such
+     * caches should be validated against the result of
+     * Service.getCacheVersion() before use.
      */
-    public static Provider.Service getService(String key) {
+    public static synchronized Provider.Service getService(String key) {
         return services.get(key);
     }
 
     /**
      * Returns the default SecureRandom service description.
-     * Call refresh() before.
      */
-    public static Provider.Service getSecureRandomService() {
-        return secureRandom;
+    public static synchronized Provider.Service getSecureRandomService() {
+        getCacheVersion();  // used for side effect of updating cache if needed
+        return cachedSecureRandomService;
     }
 
     /**
-     * Set flag needRefresh
-     *
+     * In addition to being used here when the list of providers
+     * changes, this method is also used by the Provider
+     * implementation to indicate that a provides list of services has
+     * changed.
      */
-    public static void setNeedRefresh() {
+    public static synchronized void setNeedRefresh() {
         needRefresh = true;
     }
 
     /**
-     * Refresh services info
-     *
+     * Returns the current cache version. This has the possible side
+     * effect of updating the cache if needed.
      */
-    public static void refresh() {
+    public static synchronized int getCacheVersion() {
         if (needRefresh) {
-            refreshNumber++;
-            updateServiceInfo();
+            cacheVersion++;
+            synchronized (services) {
+                services.clear();
+            }
+            cachedSecureRandomService = null;
+            for (Provider p : providers) {
+                initServiceInfo(p);
+            }
+            needRefresh = false;
         }
+        return cacheVersion;
     }
 }
diff --git a/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CRLImpl.java b/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CRLImpl.java
index 134d8f9..68ec38a 100644
--- a/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CRLImpl.java
+++ b/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CRLImpl.java
@@ -237,7 +237,7 @@
      */
     public X509CRLEntry getRevokedCertificate(X509Certificate certificate) {
         if (certificate == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("certificate == null");
         }
         if (!entriesRetrieved) {
             retrieveEntries();
diff --git a/luni/src/main/java/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java b/luni/src/main/java/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java
index d2a9c6d..2958e00 100644
--- a/luni/src/main/java/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java
+++ b/luni/src/main/java/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java
@@ -57,7 +57,7 @@
     protected Object engineGetParameter(String param)
             throws InvalidParameterException {
         if (param == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("param == null");
         }
         return null;
     }
diff --git a/luni/src/main/java/org/apache/harmony/security/x509/AuthorityKeyIdentifier.java b/luni/src/main/java/org/apache/harmony/security/x509/AuthorityKeyIdentifier.java
index be43ba7..4985aff 100644
--- a/luni/src/main/java/org/apache/harmony/security/x509/AuthorityKeyIdentifier.java
+++ b/luni/src/main/java/org/apache/harmony/security/x509/AuthorityKeyIdentifier.java
@@ -70,6 +70,34 @@
         return aki;
     }
 
+    /**
+     * The key identifier for the authority.
+     *
+     * @return key identifier or {@code null}
+     */
+    public byte[] getKeyIdentifier() {
+        return keyIdentifier;
+    }
+
+    /**
+     * The GeneralNames for this authority key identifier.
+     *
+     * @return names for the authority certificate issuer or {@code null}
+     */
+    public GeneralNames getAuthorityCertIssuer() {
+        return authorityCertIssuer;
+    }
+
+    /**
+     * The serial number of the certificate identified by this authority key
+     * identifier.
+     *
+     * @return authority's certificate serial number or {@code null}
+     */
+    public BigInteger getAuthorityCertSerialNumber() {
+        return authorityCertSerialNumber;
+    }
+
     @Override public byte[] getEncoded() {
         if (encoding == null) {
             encoding = ASN1.encode(this);
@@ -110,10 +138,10 @@
         @Override protected Object getDecodedObject(BerInputStream in) throws IOException {
             Object[] values = (Object[]) in.content;
 
-            byte[] enc = (byte[]) values[2];
+            byte[] bytes = (byte[]) values[2];
             BigInteger authorityCertSerialNumber = null;
-            if (enc != null) {
-                authorityCertSerialNumber = new BigInteger(enc);
+            if (bytes != null) {
+                authorityCertSerialNumber = new BigInteger(bytes);
             }
 
             return new AuthorityKeyIdentifier((byte[]) values[0],
diff --git a/luni/src/main/java/org/apache/harmony/security/x509/SubjectKeyIdentifier.java b/luni/src/main/java/org/apache/harmony/security/x509/SubjectKeyIdentifier.java
index 7415002..1db9598 100644
--- a/luni/src/main/java/org/apache/harmony/security/x509/SubjectKeyIdentifier.java
+++ b/luni/src/main/java/org/apache/harmony/security/x509/SubjectKeyIdentifier.java
@@ -58,6 +58,13 @@
         return res;
     }
 
+    /**
+     * The key identifier for this subject.
+     */
+    public byte[] getKeyIdentifier() {
+        return keyIdentifier;
+    }
+
     @Override public byte[] getEncoded() {
         if (encoding == null) {
             encoding = ASN1OctetString.getInstance().encode(keyIdentifier);
diff --git a/luni/src/main/java/org/apache/harmony/xml/ExpatAttributes.java b/luni/src/main/java/org/apache/harmony/xml/ExpatAttributes.java
index b92fc50..5ec632c 100644
--- a/luni/src/main/java/org/apache/harmony/xml/ExpatAttributes.java
+++ b/luni/src/main/java/org/apache/harmony/xml/ExpatAttributes.java
@@ -76,10 +76,10 @@
 
     public int getIndex(String uri, String localName) {
         if (uri == null) {
-            throw new NullPointerException("uri");
+            throw new NullPointerException("uri == null");
         }
         if (localName == null) {
-            throw new NullPointerException("local name");
+            throw new NullPointerException("localName == null");
         }
         int pointer = getPointer();
         if (pointer == 0) {
@@ -90,7 +90,7 @@
 
     public int getIndex(String qName) {
         if (qName == null) {
-            throw new NullPointerException("uri");
+            throw new NullPointerException("qName == null");
         }
         int pointer = getPointer();
         if (pointer == 0) {
@@ -101,10 +101,10 @@
 
     public String getType(String uri, String localName) {
         if (uri == null) {
-            throw new NullPointerException("uri");
+            throw new NullPointerException("uri == null");
         }
         if (localName == null) {
-            throw new NullPointerException("local name");
+            throw new NullPointerException("localName == null");
         }
         return getIndex(uri, localName) == -1 ? null : CDATA;
     }
@@ -115,10 +115,10 @@
 
     public String getValue(String uri, String localName) {
         if (uri == null) {
-            throw new NullPointerException("uri");
+            throw new NullPointerException("uri == null");
         }
         if (localName == null) {
-            throw new NullPointerException("local name");
+            throw new NullPointerException("localName == null");
         }
         int pointer = getPointer();
         if (pointer == 0) {
@@ -129,7 +129,7 @@
 
     public String getValue(String qName) {
         if (qName == null) {
-            throw new NullPointerException("qName");
+            throw new NullPointerException("qName == null");
         }
         int pointer = getPointer();
         if (pointer == 0) {
diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
index 1f1293b..af4002f 100644
--- a/luni/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
@@ -697,7 +697,7 @@
 
     public final Object setUserData(String key, Object data, UserDataHandler handler) {
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
         Map<String, UserData> map = document.getUserDataMap(this);
         UserData previous = data == null
@@ -708,7 +708,7 @@
 
     public final Object getUserData(String key) {
         if (key == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("key == null");
         }
         Map<String, UserData> map = document.getUserDataMapForRead(this);
         UserData userData = map.get(key);
diff --git a/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderFactoryImpl.java b/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderFactoryImpl.java
index 8efaa30..debbb20 100644
--- a/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderFactoryImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderFactoryImpl.java
@@ -42,7 +42,7 @@
     @Override
     public boolean getFeature(String name) throws ParserConfigurationException {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
 
         if (NAMESPACES.equals(name)) {
@@ -90,7 +90,7 @@
     public void setFeature(String name, boolean value)
             throws ParserConfigurationException {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
 
         if (NAMESPACES.equals(name)) {
diff --git a/luni/src/main/java/org/apache/harmony/xml/parsers/SAXParserFactoryImpl.java b/luni/src/main/java/org/apache/harmony/xml/parsers/SAXParserFactoryImpl.java
index 08657b9..e2e3778 100644
--- a/luni/src/main/java/org/apache/harmony/xml/parsers/SAXParserFactoryImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/parsers/SAXParserFactoryImpl.java
@@ -41,7 +41,7 @@
     @Override
     public boolean getFeature(String name) throws SAXNotRecognizedException {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
 
         if (!name.startsWith("http://xml.org/sax/features/")) {
@@ -86,7 +86,7 @@
     @Override
     public void setFeature(String name, boolean value) throws SAXNotRecognizedException {
         if (name == null) {
-            throw new NullPointerException();
+            throw new NullPointerException("name == null");
         }
 
         if (!name.startsWith("http://xml.org/sax/features/")) {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
index 4b29363..83f86ae 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
@@ -18,14 +18,12 @@
 package org.apache.harmony.xnet.provider.jsse;
 
 import java.io.IOException;
-import java.security.AccessController;
 import java.security.Key;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
-import java.security.PrivilegedExceptionAction;
 import java.security.PublicKey;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
@@ -500,7 +498,7 @@
 
         // send certificate verify for all certificates except those containing
         // fixed DH parameters
-        if (clientCert != null && !clientKeyExchange.isEmpty()) {
+        if (clientCert != null && clientCert.certs.length > 0 && !clientKeyExchange.isEmpty()) {
             // Certificate verify
             String authType = clientKey.getAlgorithm();
             DigitalSignature ds = new DigitalSignature(authType);
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCache.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCache.java
index 6619d1d..0f1fe24 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCache.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/FileClientSessionCache.java
@@ -121,7 +121,7 @@
          */
         private static String fileName(String host, int port) {
             if (host == null) {
-                throw new NullPointerException("host");
+                throw new NullPointerException("host == null");
             }
             return host + "." + port;
         }
@@ -182,7 +182,7 @@
                 byte[] sessionData) {
             String host = session.getPeerHost();
             if (sessionData == null) {
-                throw new NullPointerException("sessionData");
+                throw new NullPointerException("sessionData == null");
             }
 
             String name = fileName(host, session.getPeerPort());
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/Logger.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/Logger.java
index a2688e2..2fbbef7 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/Logger.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/Logger.java
@@ -19,8 +19,6 @@
 
 import java.io.PrintStream;
 import java.util.Locale;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import libcore.util.EmptyArray;
 
 /**
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
index 8f071f0..84f33f2 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
@@ -22,6 +22,7 @@
 import java.nio.ByteOrder;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
@@ -31,6 +32,7 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import javax.crypto.BadPaddingException;
 import javax.net.ssl.SSLException;
 import javax.security.auth.x500.X500Principal;
 import libcore.io.Memory;
@@ -52,6 +54,8 @@
 
     public static native int ENGINE_by_id(String id);
 
+    public static native int ENGINE_add(int e);
+
     public static native int ENGINE_init(int e);
 
     public static native int ENGINE_finish(int e);
@@ -84,6 +88,20 @@
 
     public static native int RSA_generate_key_ex(int modulusBits, byte[] publicExponent);
 
+    public static native int RSA_size(int pkey);
+
+    public static native int RSA_private_encrypt(int flen, byte[] from, byte[] to, int pkey,
+            int padding);
+
+    public static native int RSA_public_decrypt(int flen, byte[] from, byte[] to, int pkey,
+            int padding) throws BadPaddingException, SignatureException;
+
+    public static native int RSA_public_encrypt(int flen, byte[] from, byte[] to, int pkey,
+            int padding);
+
+    public static native int RSA_private_decrypt(int flen, byte[] from, byte[] to, int pkey,
+            int padding) throws BadPaddingException, SignatureException;
+
     /**
      * @return array of {n, e}
      */
@@ -172,6 +190,8 @@
 
     public static native int RAND_load_file(String filename, long max_bytes);
 
+    public static native void RAND_bytes(byte[] output);
+
     // --- X509_NAME -----------------------------------------------------------
 
     public static int X509_NAME_hash(X500Principal principal) {
@@ -333,6 +353,10 @@
     public static final int EVP_PKEY_DH  = 28;  // NID_dhKeyAgreement
     public static final int EVP_PKEY_EC  = 408; // NID_X9_62_id_ecPublicKey
 
+    // RSA padding modes from rsa.h
+    public static final int RSA_PKCS1_PADDING = 1;
+    public static final int RSA_NO_PADDING    = 3;
+
     // SSL mode from ssl.h
     public static final long SSL_MODE_HANDSHAKE_CUTTHROUGH = 0x00000040L;
 
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLCipherRSA.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLCipherRSA.java
new file mode 100644
index 0000000..a11ffa9
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLCipherRSA.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2012 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+import libcore.util.EmptyArray;
+
+public abstract class OpenSSLCipherRSA extends CipherSpi {
+    /**
+     * The current OpenSSL key we're operating on.
+     */
+    private OpenSSLKey key;
+
+    /**
+     * Current key type: private or public.
+     */
+    private boolean usingPrivateKey;
+
+    /**
+     * Current cipher mode: encrypting or decrypting.
+     */
+    private boolean encrypting;
+
+    /**
+     * Buffer for operations
+     */
+    private byte[] buffer;
+
+    /**
+     * Current offset in the buffer.
+     */
+    private int bufferOffset;
+
+    /**
+     * Flag that indicates an exception should be thrown when the input is too
+     * large during doFinal.
+     */
+    private boolean inputTooLarge;
+
+    /**
+     * Current padding mode
+     */
+    private int padding = NativeCrypto.RSA_PKCS1_PADDING;
+
+    protected OpenSSLCipherRSA(int padding) {
+        this.padding = padding;
+    }
+
+    @Override
+    protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+        final String modeUpper = mode.toUpperCase();
+        if ("NONE".equals(modeUpper) || "ECB".equals(modeUpper)) {
+            return;
+        }
+
+        throw new NoSuchAlgorithmException("mode not supported: " + mode);
+    }
+
+    @Override
+    protected void engineSetPadding(String padding) throws NoSuchPaddingException {
+        final String paddingUpper = padding.toUpperCase();
+        if ("PKCS1PADDING".equals(paddingUpper)) {
+            this.padding = NativeCrypto.RSA_PKCS1_PADDING;
+            return;
+        }
+        if ("NOPADDING".equals(paddingUpper)) {
+            this.padding = NativeCrypto.RSA_NO_PADDING;
+            return;
+        }
+
+        throw new NoSuchPaddingException("padding not supported: " + padding);
+    }
+
+    @Override
+    protected int engineGetBlockSize() {
+        return 0;
+    }
+
+    @Override
+    protected int engineGetOutputSize(int inputLen) {
+        if (key == null) {
+            throw new IllegalStateException("cipher is not initialized");
+        }
+
+        return buffer.length;
+    }
+
+    @Override
+    protected byte[] engineGetIV() {
+        return null;
+    }
+
+    @Override
+    protected AlgorithmParameters engineGetParameters() {
+        return null;
+    }
+
+    private void engineInitInternal(int opmode, Key key) throws InvalidKeyException {
+        if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) {
+            encrypting = true;
+        } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) {
+            encrypting = false;
+        } else {
+            throw new InvalidParameterException("Unsupported opmode " + opmode);
+        }
+
+        if (key instanceof OpenSSLRSAPrivateKey) {
+            OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) key;
+            usingPrivateKey = true;
+            this.key = rsaPrivateKey.getOpenSSLKey();
+        } else if (key instanceof RSAPrivateCrtKey) {
+            RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) key;
+            usingPrivateKey = true;
+            this.key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey);
+        } else if (key instanceof RSAPrivateKey) {
+            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) key;
+            usingPrivateKey = true;
+            this.key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey);
+        } else if (key instanceof OpenSSLRSAPublicKey) {
+            OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) key;
+            usingPrivateKey = false;
+            this.key = rsaPublicKey.getOpenSSLKey();
+        } else if (key instanceof RSAPublicKey) {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) key;
+            usingPrivateKey = false;
+            this.key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey);
+        } else {
+            throw new InvalidKeyException("Need RSA private or public key");
+        }
+
+        buffer = new byte[NativeCrypto.RSA_size(this.key.getPkeyContext())];
+        inputTooLarge = false;
+    }
+
+    @Override
+    protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
+        engineInitInternal(opmode, key);
+    }
+
+    @Override
+    protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+            SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (params != null) {
+            throw new InvalidAlgorithmParameterException("unknown param type: "
+                    + params.getClass().getName());
+        }
+
+        engineInitInternal(opmode, key);
+    }
+
+    @Override
+    protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (params != null) {
+            throw new InvalidAlgorithmParameterException("unknown param type: "
+                    + params.getClass().getName());
+        }
+
+        engineInitInternal(opmode, key);
+    }
+
+    @Override
+    protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+        if (bufferOffset + inputLen > buffer.length) {
+            inputTooLarge = true;
+            return EmptyArray.BYTE;
+        }
+
+        System.arraycopy(input, inputOffset, buffer, bufferOffset, inputLen);
+        bufferOffset += inputLen;
+        return EmptyArray.BYTE;
+    }
+
+    @Override
+    protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
+            int outputOffset) throws ShortBufferException {
+        engineUpdate(input, inputOffset, inputLen);
+        return 0;
+    }
+
+    @Override
+    protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+        if (input != null) {
+            engineUpdate(input, inputOffset, inputLen);
+        }
+
+        if (inputTooLarge) {
+            throw new IllegalBlockSizeException("input must be under " + buffer.length + " bytes");
+        }
+
+        final byte[] tmpBuf;
+        if (bufferOffset != buffer.length) {
+            if (padding == NativeCrypto.RSA_NO_PADDING) {
+                tmpBuf = new byte[buffer.length];
+                System.arraycopy(buffer, 0, tmpBuf, buffer.length - bufferOffset, bufferOffset);
+            } else {
+                tmpBuf = Arrays.copyOf(buffer, bufferOffset);
+            }
+        } else {
+            tmpBuf = buffer;
+        }
+
+        byte[] output = new byte[buffer.length];
+        int resultSize;
+        if (encrypting) {
+            if (usingPrivateKey) {
+                resultSize = NativeCrypto.RSA_private_encrypt(tmpBuf.length, tmpBuf, output,
+                                                              key.getPkeyContext(), padding);
+            } else {
+                resultSize = NativeCrypto.RSA_public_encrypt(tmpBuf.length, tmpBuf, output,
+                                                             key.getPkeyContext(), padding);
+            }
+        } else {
+            try {
+                if (usingPrivateKey) {
+                    resultSize = NativeCrypto.RSA_private_decrypt(tmpBuf.length, tmpBuf, output,
+                                                                  key.getPkeyContext(), padding);
+                } else {
+                    resultSize = NativeCrypto.RSA_public_decrypt(tmpBuf.length, tmpBuf, output,
+                                                                 key.getPkeyContext(), padding);
+                }
+            } catch (SignatureException e) {
+                IllegalBlockSizeException newE = new IllegalBlockSizeException();
+                newE.initCause(e);
+                throw newE;
+            }
+        }
+        if (!encrypting && resultSize != output.length) {
+            output = Arrays.copyOf(output, resultSize);
+        }
+
+        bufferOffset = 0;
+        return output;
+    }
+
+    @Override
+    protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
+            int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        byte[] b = engineDoFinal(input, inputOffset, inputLen);
+
+        final int lastOffset = outputOffset + b.length;
+        if (lastOffset > output.length) {
+            throw new ShortBufferException("output buffer is too small " + output.length + " < "
+                    + lastOffset);
+        }
+
+        System.arraycopy(b, 0, output, outputOffset, b.length);
+        return b.length;
+    }
+
+    @Override
+    protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException {
+        try {
+            byte[] encoded = key.getEncoded();
+            return engineDoFinal(encoded, 0, encoded.length);
+        } catch (BadPaddingException e) {
+            IllegalBlockSizeException newE = new IllegalBlockSizeException();
+            newE.initCause(e);
+            throw newE;
+        }
+    }
+
+    @Override
+    protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
+            int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException {
+        try {
+            byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+            if (wrappedKeyType == Cipher.PUBLIC_KEY) {
+                KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
+                return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
+            } else if (wrappedKeyType == Cipher.PRIVATE_KEY) {
+                KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
+                return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+            } else if (wrappedKeyType == Cipher.SECRET_KEY) {
+                return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+            } else {
+                throw new UnsupportedOperationException("wrappedKeyType == " + wrappedKeyType);
+            }
+        } catch (IllegalBlockSizeException e) {
+            throw new InvalidKeyException(e);
+        } catch (BadPaddingException e) {
+            throw new InvalidKeyException(e);
+        } catch (InvalidKeySpecException e) {
+            throw new InvalidKeyException(e);
+        }
+    }
+
+    public static class PKCS1 extends OpenSSLCipherRSA {
+        public PKCS1() {
+            super(NativeCrypto.RSA_PKCS1_PADDING);
+        }
+    }
+
+    public static class Raw extends OpenSSLCipherRSA {
+        public Raw() {
+            super(NativeCrypto.RSA_NO_PADDING);
+        }
+    }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPrivateKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPrivateKey.java
index 7cd16f7..761b08e 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPrivateKey.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPrivateKey.java
@@ -120,6 +120,10 @@
         return key.getPkeyContext();
     }
 
+    public String getPkeyAlias() {
+        return key.getAlias();
+    }
+
     @Override
     public boolean equals(Object o) {
         if (o == this) {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLEngine.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLEngine.java
index e91e6d8..d01dc62 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLEngine.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLEngine.java
@@ -24,6 +24,8 @@
         NativeCrypto.ENGINE_load_dynamic();
     }
 
+    private static final Object mLoadingLock = new Object();
+
     /** The ENGINE's native handle. */
     private final int ctx;
 
@@ -32,10 +34,14 @@
             throw new NullPointerException("engine == null");
         }
 
-        final int engineCtx = NativeCrypto.ENGINE_by_id(engine);
+        final int engineCtx;
+        synchronized (mLoadingLock) {
+            engineCtx = NativeCrypto.ENGINE_by_id(engine);
+            if (engineCtx == 0) {
+                throw new IllegalArgumentException("Unknown ENGINE id: " + engine);
+            }
 
-        if (engineCtx == 0) {
-            throw new IllegalArgumentException("Unknown ENGINE id: " + engine);
+            NativeCrypto.ENGINE_add(engineCtx);
         }
 
         return new OpenSSLEngine(engineCtx);
@@ -45,6 +51,7 @@
         ctx = engineCtx;
 
         if (NativeCrypto.ENGINE_init(engineCtx) == 0) {
+            NativeCrypto.ENGINE_free(engineCtx);
             throw new IllegalArgumentException("Could not initialize engine");
         }
     }
@@ -62,9 +69,9 @@
         final int keyType = NativeCrypto.EVP_PKEY_type(keyRef);
         switch (keyType) {
             case NativeCrypto.EVP_PKEY_RSA:
-                return OpenSSLRSAPrivateKey.getInstance(new OpenSSLKey(keyRef, this));
+                return OpenSSLRSAPrivateKey.getInstance(new OpenSSLKey(keyRef, this, id));
             case NativeCrypto.EVP_PKEY_DSA:
-                return new OpenSSLDSAPrivateKey(new OpenSSLKey(keyRef, this));
+                return new OpenSSLDSAPrivateKey(new OpenSSLKey(keyRef, this, id));
             default:
                 throw new InvalidKeyException("Unknown key type: " + keyType);
         }
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLKey.java
index 90eb0e2..b8b9f69 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLKey.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLKey.java
@@ -21,14 +21,18 @@
 
     private final OpenSSLEngine engine;
 
+    private final String alias;
+
     OpenSSLKey(int ctx) {
         this.ctx = ctx;
         engine = null;
+        alias = null;
     }
 
-    OpenSSLKey(int ctx, OpenSSLEngine engine) {
+    OpenSSLKey(int ctx, OpenSSLEngine engine, String alias) {
         this.ctx = ctx;
         this.engine = engine;
+        this.alias = alias;
     }
 
     int getPkeyContext() {
@@ -43,6 +47,10 @@
         return engine != null;
     }
 
+    String getAlias() {
+        return alias;
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
index 97753cf..e1d0fb0 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
@@ -108,5 +108,22 @@
         put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
         put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
         put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
+
+        put("Signature.NONEwithRSA", OpenSSLSignatureRawRSA.class.getName());
+
+        // SecureRandom
+        /*
+         * We have to specify SHA1PRNG because various documentation mentions
+         * that algorithm by name instead of just recommending calling
+         * "new SecureRandom()"
+         */
+        put("SecureRandom.SHA1PRNG", OpenSSLRandom.class.getName());
+        put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
+
+        // Cipher
+        put("Cipher.RSA/ECB/NoPadding", OpenSSLCipherRSA.Raw.class.getName());
+        put("Alg.Alias.Cipher.RSA/None/NoPadding", "RSA/ECB/NoPadding");
+        put("Cipher.RSA/ECB/PKCS1Padding", OpenSSLCipherRSA.PKCS1.class.getName());
+        put("Alg.Alias.Cipher.RSA/None/PKCS1Padding", "RSA/ECB/PKCS1Padding");
     }
 }
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java
index 8376515..48e1494 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java
@@ -201,6 +201,16 @@
             if (getOpenSSLKey().equals(other.getOpenSSLKey())) {
                 return true;
             }
+
+            /*
+             * If this key is ENGINE-based, it could be equivalent to another
+             * ENGINE-based key. The modulus may be equal, but that occurrence
+             * should be so improbably low as to never happen.
+             */
+            if (getOpenSSLKey().isEngineBased() || other.getOpenSSLKey().isEngineBased()) {
+                return publicExponent.equals(other.getPublicExponent())
+                        && getModulus().equals(other.getModulus());
+            }
         }
 
         if (o instanceof RSAPrivateCrtKey) {
@@ -232,11 +242,11 @@
     public String toString() {
         final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateCrtKey{");
 
-        if (getOpenSSLKey().isEngineBased()) {
+        final boolean engineBased = getOpenSSLKey().isEngineBased();
+        if (engineBased) {
             sb.append("key=");
             sb.append(getOpenSSLKey());
             sb.append('}');
-            return sb.toString();
         }
 
         ensureReadParams();
@@ -250,9 +260,11 @@
             sb.append(',');
         }
 
-        sb.append("privateExponent=");
-        sb.append(getPrivateExponent().toString(16));
-        sb.append(',');
+        if (!engineBased) {
+            sb.append("privateExponent=");
+            sb.append(getPrivateExponent().toString(16));
+            sb.append(',');
+        }
 
         if (primeP != null) {
             sb.append("primeP=");
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java
index c9fa178..5c2f075 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java
@@ -180,6 +180,10 @@
         return key.getPkeyContext();
     }
 
+    public String getPkeyAlias() {
+        return key.getAlias();
+    }
+
     @Override
     public boolean equals(Object o) {
         if (o == this) {
@@ -196,6 +200,15 @@
             if (key.equals(other.getOpenSSLKey())) {
                 return true;
             }
+
+            /*
+             * If this key is ENGINE-based, it could be equivalent to another
+             * ENGINE-based key. The modulus may be equal, but that occurrence
+             * should be so improbably low as to never happen.
+             */
+            if (key.isEngineBased() || other.getOpenSSLKey().isEngineBased()) {
+                return modulus.equals(other.getModulus());
+            }
         }
 
         if (o instanceof RSAPrivateKey) {
@@ -226,11 +239,11 @@
     public String toString() {
         final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateKey{");
 
-        if (key.isEngineBased()) {
+        final boolean engineBased = key.isEngineBased();
+        if (engineBased) {
             sb.append("key=");
             sb.append(key);
             sb.append('}');
-            return sb.toString();
         }
 
         ensureReadParams();
@@ -238,9 +251,11 @@
         sb.append(modulus.toString(16));
         sb.append(',');
 
-        sb.append("privateExponent=");
-        sb.append(privateExponent.toString(16));
-        sb.append(',');
+        if (!engineBased) {
+            sb.append("privateExponent=");
+            sb.append(privateExponent.toString(16));
+            sb.append(',');
+        }
 
         return sb.toString();
     }
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRandom.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRandom.java
new file mode 100644
index 0000000..fd011f0
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRandom.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.io.Serializable;
+import java.security.SecureRandomSpi;
+
+public class OpenSSLRandom extends SecureRandomSpi implements Serializable {
+    private static final long serialVersionUID = 8506210602917522860L;
+
+    @Override
+    protected void engineSetSeed(byte[] seed) {
+        NativeCrypto.RAND_seed(seed);
+    }
+
+    @Override
+    protected void engineNextBytes(byte[] bytes) {
+        NativeCrypto.RAND_bytes(bytes);
+    }
+
+    @Override
+    protected byte[] engineGenerateSeed(int numBytes) {
+        byte[] output = new byte[numBytes];
+        NativeCrypto.RAND_bytes(output);
+        return output;
+    }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java
index 35603df..003122f 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java
@@ -366,9 +366,7 @@
     /**
      * Returns the object which is bound to the the input parameter name.
      * This name is a sort of link to the data of the SSL session's application
-     * layer, if any exists. The search for this link is monitored, as a matter
-     * of security, by the full machinery of the <code>AccessController</code>
-     * class.
+     * layer, if any exists.
      *
      * @param name the name of the binding to find.
      * @return the value bound to that name, or null if the binding does not
@@ -384,9 +382,7 @@
 
     /**
      * Returns an array with the names (sort of links) of all the data
-     * objects of the application layer bound into the SSL session. The search
-     * for this link is monitored, as a matter of security, by the full
-     * machinery of the <code>AccessController</code> class.
+     * objects of the application layer bound into the SSL session.
      *
      * @return a non-null (possibly empty) array of names of the data objects
      *         bound to this SSL session.
@@ -399,9 +395,7 @@
      * A link (name) with the specified value object of the SSL session's
      * application layer data is created or replaced. If the new (or existing)
      * value object implements the <code>SSLSessionBindingListener</code>
-     * interface, that object will be notified in due course. These links-to
-     * -data bounds are monitored, as a matter of security, by the full
-     * machinery of the <code>AccessController</code> class.
+     * interface, that object will be notified in due course.
      *
      * @param name the name of the link (no null are
      *            accepted!)
@@ -432,10 +426,6 @@
      * <p>If the value object implements the <code>SSLSessionBindingListener</code>
      * interface, the object will receive a <code>valueUnbound</code> notification.
      *
-     * <p>These links-to -data bounds are
-     * monitored, as a matter of security, by the full machinery of the
-     * <code>AccessController</code> class.
-     *
      * @param name the name of the link (no null are
      *            accepted!)
      * @throws <code>IllegalArgumentException</code> if the argument is null.
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignatureRawRSA.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignatureRawRSA.java
new file mode 100644
index 0000000..289af30
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignatureRawRSA.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2012 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+
+/**
+ * Implements the JDK Signature interface needed for RAW RSA signature
+ * generation and verification using OpenSSL.
+ */
+public class OpenSSLSignatureRawRSA extends Signature {
+    /**
+     * The current OpenSSL key we're operating on.
+     */
+    private OpenSSLKey key;
+
+    /**
+     * Buffer to hold value to be signed or verified.
+     */
+    private byte[] inputBuffer;
+
+    /**
+     * Current offset in input buffer.
+     */
+    private int inputOffset;
+
+    /**
+     * Provides a flag to specify when the input is too long.
+     */
+    private boolean inputIsTooLong;
+
+    /**
+     * Creates a new OpenSSLSignature instance for the given algorithm name.
+     */
+    public OpenSSLSignatureRawRSA() throws NoSuchAlgorithmException {
+        super("NONEwithRSA");
+    }
+
+    @Override
+    protected void engineUpdate(byte input) {
+        final int oldOffset = inputOffset++;
+
+        if (inputOffset > inputBuffer.length) {
+            inputIsTooLong = true;
+            return;
+        }
+
+        inputBuffer[oldOffset] = input;
+    }
+
+    @Override
+    protected void engineUpdate(byte[] input, int offset, int len) {
+        final int oldOffset = inputOffset;
+        inputOffset += len;
+
+        if (inputOffset > inputBuffer.length) {
+            inputIsTooLong = true;
+            return;
+        }
+
+        System.arraycopy(input, offset, inputBuffer, oldOffset, len);
+    }
+
+    @Override
+    protected Object engineGetParameter(String param) throws InvalidParameterException {
+        return null;
+    }
+
+    @Override
+    protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+        if (privateKey instanceof OpenSSLRSAPrivateKey) {
+            OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) privateKey;
+            key = rsaPrivateKey.getOpenSSLKey();
+        } else if (privateKey instanceof RSAPrivateCrtKey) {
+            RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey;
+            key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey);
+        } else if (privateKey instanceof RSAPrivateKey) {
+            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
+            key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey);
+        } else {
+            throw new InvalidKeyException("Need DSA or RSA private key");
+        }
+
+        // Allocate buffer according to RSA modulus size.
+        int maxSize = NativeCrypto.RSA_size(key.getPkeyContext());
+        inputBuffer = new byte[maxSize];
+        inputOffset = 0;
+    }
+
+    @Override
+    protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+        if (publicKey instanceof OpenSSLRSAPublicKey) {
+            OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) publicKey;
+            key = rsaPublicKey.getOpenSSLKey();
+        } else if (publicKey instanceof RSAPublicKey) {
+            RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
+            key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey);
+        } else {
+            throw new InvalidKeyException("Need DSA or RSA public key");
+        }
+
+        // Allocate buffer according to RSA modulus size.
+        int maxSize = NativeCrypto.RSA_size(key.getPkeyContext());
+        inputBuffer = new byte[maxSize];
+        inputOffset = 0;
+    }
+
+    @Override
+    protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
+    }
+
+    @Override
+    protected byte[] engineSign() throws SignatureException {
+        if (key == null) {
+            // This can't actually happen, but you never know...
+            throw new SignatureException("Need RSA private key");
+        }
+
+        if (inputIsTooLong) {
+            throw new SignatureException("input length " + inputOffset + " != "
+                    + inputBuffer.length + " (modulus size)");
+        }
+
+        byte[] outputBuffer = new byte[inputBuffer.length];
+        try {
+            NativeCrypto.RSA_private_encrypt(inputOffset, inputBuffer, outputBuffer,
+                    key.getPkeyContext(), NativeCrypto.RSA_PKCS1_PADDING);
+            return outputBuffer;
+        } catch (Exception ex) {
+            throw new SignatureException(ex);
+        } finally {
+            inputOffset = 0;
+        }
+    }
+
+    @Override
+    protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+        if (key == null) {
+            // This can't actually happen, but you never know...
+            throw new SignatureException("Need RSA public key");
+        }
+
+        if (inputIsTooLong) {
+            return false;
+        }
+
+        byte[] outputBuffer = new byte[inputBuffer.length];
+        try {
+            final int resultSize;
+            try {
+                resultSize = NativeCrypto.RSA_public_decrypt(sigBytes.length, sigBytes,
+                        outputBuffer, key.getPkeyContext(), NativeCrypto.RSA_PKCS1_PADDING);
+            } catch (SignatureException e) {
+                throw e;
+            } catch (Exception e) {
+                return false;
+            }
+            /* Make this constant time by comparing every byte. */
+            boolean matches = (resultSize == inputOffset);
+            for (int i = 0; i < resultSize; i++) {
+                if (inputBuffer[i] != outputBuffer[i]) {
+                    matches = false;
+                }
+            }
+            return matches;
+        } catch (Exception ex) {
+            throw new SignatureException(ex);
+        } finally {
+            inputOffset = 0;
+        }
+    }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
index 42b7500..b258bae 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
@@ -861,12 +861,13 @@
             }
         }
 
-        NativeCrypto.SSL_interrupt(sslNativePointer);
-
         synchronized (this) {
+
+            // Interrupt any outstanding reads or writes before taking the writeLock and readLock
+            NativeCrypto.SSL_interrupt(sslNativePointer);
+
             synchronized (writeLock) {
                 synchronized (readLock) {
-
                     // Shut down the SSL connection, per se.
                     try {
                         if (handshakeStarted) {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
index c5e1838..fa8d291 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
@@ -19,7 +19,6 @@
 
 import java.io.IOException;
 import java.math.BigInteger;
-import java.security.AccessController;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
@@ -659,7 +658,7 @@
         } else {
             if ((parameters.getNeedClientAuth() && clientCert == null)
                     || clientKeyExchange == null
-                    || (clientCert != null
+                    || (clientCert != null && clientCert.certs.length > 0
                             && !clientKeyExchange.isEmpty()
                             && certificateVerify == null)) {
                 unexpectedMessage();
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStore.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStore.java
index 54116a7..abb6e55 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStore.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStore.java
@@ -16,6 +16,11 @@
 
 package org.apache.harmony.xnet.provider.jsse;
 
+import org.apache.harmony.security.x501.Name;
+import org.apache.harmony.security.x509.AuthorityKeyIdentifier;
+import org.apache.harmony.security.x509.GeneralName;
+import org.apache.harmony.security.x509.GeneralNames;
+import org.apache.harmony.security.x509.SubjectKeyIdentifier;
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -23,19 +28,20 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.security.KeyStoreSpi;
-import java.security.PublicKey;
-import java.security.cert.CertSelector;
+import java.math.BigInteger;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import javax.security.auth.x500.X500Principal;
 import libcore.io.IoUtils;
+import libcore.util.Objects;
 
 /**
  * A source for trusted root certificate authority (CA) certificates
@@ -366,6 +372,109 @@
         return null;
     }
 
+    private static AuthorityKeyIdentifier getAuthorityKeyIdentifier(X509Certificate cert) {
+        final byte[] akidBytes = cert.getExtensionValue("2.5.29.35");
+        if (akidBytes == null) {
+            return null;
+        }
+
+        try {
+            return AuthorityKeyIdentifier.decode(akidBytes);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    private static SubjectKeyIdentifier getSubjectKeyIdentifier(X509Certificate cert) {
+        final byte[] skidBytes = cert.getExtensionValue("2.5.29.14");
+        if (skidBytes == null) {
+            return null;
+        }
+
+        try {
+            return SubjectKeyIdentifier.decode(skidBytes);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    private static boolean isSelfSignedCertificate(X509Certificate cert) {
+        if (!Objects.equal(cert.getSubjectX500Principal(), cert.getIssuerX500Principal())) {
+            return false;
+        }
+
+        final AuthorityKeyIdentifier akid = getAuthorityKeyIdentifier(cert);
+        if (akid != null) {
+            final byte[] akidKeyId = akid.getKeyIdentifier();
+            if (akidKeyId != null) {
+                final SubjectKeyIdentifier skid = getSubjectKeyIdentifier(cert);
+                if (!Arrays.equals(akidKeyId, skid.getKeyIdentifier())) {
+                    return false;
+                }
+            }
+
+            final BigInteger akidSerial = akid.getAuthorityCertSerialNumber();
+            if (akidSerial != null && !akidSerial.equals(cert.getSerialNumber())) {
+                return false;
+            }
+
+            final GeneralNames possibleIssuerNames = akid.getAuthorityCertIssuer();
+            if (possibleIssuerNames != null) {
+                GeneralName issuerName = null;
+
+                /* Get the first Directory Name (DN) to match how OpenSSL works. */
+                for (GeneralName possibleName : possibleIssuerNames.getNames()) {
+                    if (possibleName.getTag() == GeneralName.DIR_NAME) {
+                        issuerName = possibleName;
+                        break;
+                    }
+                }
+
+                if (issuerName != null) {
+                    final String issuerCanonical = ((Name) issuerName.getName())
+                            .getName(X500Principal.CANONICAL);
+
+                    try {
+                        final String subjectCanonical = new Name(cert.getSubjectX500Principal()
+                                .getEncoded()).getName(X500Principal.CANONICAL);
+                        if (!issuerCanonical.equals(subjectCanonical)) {
+                            return false;
+                        }
+                    } catch (IOException ignored) {
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Attempt to build a certificate chain from the supplied {@code leaf}
+     * argument through the chain of issuers as high up as known. If the chain
+     * can't be completed, the most complete chain available will be returned.
+     * This means that a list with only the {@code leaf} certificate is returned
+     * if no issuer certificates could be found.
+     */
+    public List<X509Certificate> getCertificateChain(X509Certificate leaf) {
+        final List<X509Certificate> chain = new ArrayList<X509Certificate>();
+        chain.add(leaf);
+
+        for (int i = 0; true; i++) {
+            X509Certificate cert = chain.get(i);
+            if (isSelfSignedCertificate(cert)) {
+                break;
+            }
+            X509Certificate issuer = findIssuer(cert);
+            if (issuer == null) {
+                break;
+            }
+            chain.add(issuer);
+        }
+
+        return chain;
+    }
+
     // like java.security.cert.CertSelector but with X509Certificate and without cloning
     private static interface CertSelector {
         public boolean match(X509Certificate cert);
diff --git a/luni/src/main/native/JniException.cpp b/luni/src/main/native/JniException.cpp
index 6626448..c733db4 100644
--- a/luni/src/main/native/JniException.cpp
+++ b/luni/src/main/native/JniException.cpp
@@ -17,22 +17,27 @@
 #include "JniException.h"
 #include "JNIHelp.h"
 
-bool maybeThrowIcuException(JNIEnv* env, UErrorCode error) {
+bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error) {
     if (U_SUCCESS(error)) {
         return false;
     }
-    const char* message = u_errorName(error);
+    const char* exceptionClass;
     switch (error) {
     case U_ILLEGAL_ARGUMENT_ERROR:
-        return jniThrowException(env, "java/lang/IllegalArgumentException", message);
+        exceptionClass = "java/lang/IllegalArgumentException";
+        break;
     case U_INDEX_OUTOFBOUNDS_ERROR:
     case U_BUFFER_OVERFLOW_ERROR:
-        return jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", message);
+        exceptionClass = "java/lang/ArrayIndexOutOfBoundsException";
+        break;
     case U_UNSUPPORTED_ERROR:
-        return jniThrowException(env, "java/lang/UnsupportedOperationException", message);
+        exceptionClass = "java/lang/UnsupportedOperationException";
+        break;
     default:
-        return jniThrowRuntimeException(env, message);
+        exceptionClass = "java/lang/RuntimeException";
+        break;
     }
+    return jniThrowExceptionFmt(env, exceptionClass, "%s failed: %s", function, u_errorName(error));
 }
 
 void jniThrowExceptionWithErrno(JNIEnv* env, const char* exceptionClassName, int error) {
diff --git a/luni/src/main/native/JniException.h b/luni/src/main/native/JniException.h
index b3447d2..cece2aa 100644
--- a/luni/src/main/native/JniException.h
+++ b/luni/src/main/native/JniException.h
@@ -25,6 +25,6 @@
 void jniThrowOutOfMemoryError(JNIEnv* env, const char* message);
 void jniThrowSocketException(JNIEnv* env, int error);
 
-bool maybeThrowIcuException(JNIEnv* env, UErrorCode error);
+bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error);
 
 #endif  // JNI_EXCEPTION_H_included
diff --git a/luni/src/main/native/java_text_Bidi.cpp b/luni/src/main/native/java_text_Bidi.cpp
index 93c02bb..01bca09 100644
--- a/luni/src/main/native/java_text_Bidi.cpp
+++ b/luni/src/main/native/java_text_Bidi.cpp
@@ -88,18 +88,18 @@
     }
     UErrorCode err = U_ZERO_ERROR;
     ubidi_setPara(data->uBiDi(), chars.get(), length, paraLevel, data->embeddingLevels(), &err);
-    maybeThrowIcuException(env, err);
+    maybeThrowIcuException(env, "ubidi_setPara", err);
 }
 
 static jlong Bidi_ubidi_setLine(JNIEnv* env, jclass, jlong ptr, jint start, jint limit) {
     UErrorCode status = U_ZERO_ERROR;
     UBiDi* sized = ubidi_openSized(limit - start, 0, &status);
-    if (maybeThrowIcuException(env, status)) {
+    if (maybeThrowIcuException(env, "ubidi_openSized", status)) {
         return 0;
     }
     UniquePtr<BiDiData> lineData(new BiDiData(sized));
     ubidi_setLine(uBiDi(ptr), start, limit, lineData->uBiDi(), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ubidi_setLine", status);
     return reinterpret_cast<uintptr_t>(lineData.release());
 }
 
@@ -118,7 +118,7 @@
 static jbyteArray Bidi_ubidi_getLevels(JNIEnv* env, jclass, jlong ptr) {
     UErrorCode status = U_ZERO_ERROR;
     const UBiDiLevel* levels = ubidi_getLevels(uBiDi(ptr), &status);
-    if (maybeThrowIcuException(env, status)) {
+    if (maybeThrowIcuException(env, "ubidi_getLevels", status)) {
         return NULL;
     }
     int len = ubidi_getLength(uBiDi(ptr));
@@ -130,7 +130,7 @@
 static jint Bidi_ubidi_countRuns(JNIEnv* env, jclass, jlong ptr) {
     UErrorCode status = U_ZERO_ERROR;
     int count = ubidi_countRuns(uBiDi(ptr), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ubidi_countRuns", status);
     return count;
 }
 
@@ -141,7 +141,7 @@
     UBiDi* ubidi = uBiDi(ptr);
     UErrorCode status = U_ZERO_ERROR;
     int runCount = ubidi_countRuns(ubidi, &status);
-    if (maybeThrowIcuException(env, status)) {
+    if (maybeThrowIcuException(env, "ubidi_countRuns", status)) {
         return NULL;
     }
     jmethodID bidiRunConstructor = env->GetMethodID(JniConstants::bidiRunClass, "<init>", "(III)V");
diff --git a/luni/src/main/native/java_util_regex_Matcher.cpp b/luni/src/main/native/java_util_regex_Matcher.cpp
index 0f91bd5..6116d2b 100644
--- a/luni/src/main/native/java_util_regex_Matcher.cpp
+++ b/luni/src/main/native/java_util_regex_Matcher.cpp
@@ -71,7 +71,7 @@
         if (mJavaInput) {
             mEnv->ReleaseStringChars(mJavaInput, mChars);
         }
-        maybeThrowIcuException(mEnv, mStatus);
+        maybeThrowIcuException(mEnv, "utext_close", mStatus);
     }
 
     RegexMatcher* operator->() {
@@ -173,7 +173,7 @@
     RegexPattern* pattern = reinterpret_cast<RegexPattern*>(static_cast<uintptr_t>(patternAddr));
     UErrorCode status = U_ZERO_ERROR;
     RegexMatcher* result = pattern->matcher(status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "RegexPattern::matcher", status);
     return static_cast<jint>(reinterpret_cast<uintptr_t>(result));
 }
 
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 5a07694..5224420 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -59,27 +59,37 @@
 #include <time.h>
 #include <unistd.h>
 
+// TODO: put this in a header file and use it everywhere!
+// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
+// It goes in the private: declarations in a class.
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+    TypeName(const TypeName&); \
+    void operator=(const TypeName&)
+
 class ScopedResourceBundle {
-public:
-    ScopedResourceBundle(UResourceBundle* bundle) : mBundle(bundle) {
+ public:
+  ScopedResourceBundle(UResourceBundle* bundle) : bundle_(bundle) {
+  }
+
+  ~ScopedResourceBundle() {
+    if (bundle_ != NULL) {
+      ures_close(bundle_);
     }
+  }
 
-    ~ScopedResourceBundle() {
-        if (mBundle != NULL) {
-            ures_close(mBundle);
-        }
-    }
+  UResourceBundle* get() {
+    return bundle_;
+  }
 
-    UResourceBundle* get() {
-        return mBundle;
-    }
+  bool hasKey(const char* key) {
+    UErrorCode status = U_ZERO_ERROR;
+    ures_getStringByKey(bundle_, key, NULL, &status);
+    return U_SUCCESS(status);
+  }
 
-private:
-    UResourceBundle* mBundle;
-
-    // Disallow copy and assignment.
-    ScopedResourceBundle(const ScopedResourceBundle&);
-    void operator=(const ScopedResourceBundle&);
+ private:
+  UResourceBundle* bundle_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedResourceBundle);
 };
 
 Locale getLocale(JNIEnv* env, jstring localeName) {
@@ -302,14 +312,25 @@
 }
 
 static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, UResourceBundle* bundle, int index) {
-    UErrorCode status = U_ZERO_ERROR;
-    int charCount;
-    const UChar* chars = ures_getStringByIndex(bundle, index, &charCount, &status);
-    if (U_SUCCESS(status)) {
-        setStringField(env, obj, fieldName, env->NewString(chars, charCount));
-    } else {
-        ALOGE("Error setting String field %s from ICU resource: %s", fieldName, u_errorName(status));
-    }
+  UErrorCode status = U_ZERO_ERROR;
+  int charCount;
+  const UChar* chars = ures_getStringByIndex(bundle, index, &charCount, &status);
+  if (U_SUCCESS(status)) {
+    setStringField(env, obj, fieldName, env->NewString(chars, charCount));
+  } else {
+    ALOGE("Error setting String field %s from ICU resource (index %d): %s", fieldName, index, u_errorName(status));
+  }
+}
+
+static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, UResourceBundle* bundle, const char* key) {
+  UErrorCode status = U_ZERO_ERROR;
+  int charCount;
+  const UChar* chars = ures_getStringByKey(bundle, key, &charCount, &status);
+  if (U_SUCCESS(status)) {
+    setStringField(env, obj, fieldName, env->NewString(chars, charCount));
+  } else {
+    ALOGE("Error setting String field %s from ICU resource (key %s): %s", fieldName, key, u_errorName(status));
+  }
 }
 
 static void setCharField(JNIEnv* env, jobject obj, const char* fieldName, const UnicodeString& value) {
@@ -361,80 +382,159 @@
     setCharField(env, obj, "zeroDigit", dfs.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol));
 }
 
+
+// Iterates up through the locale hierarchy. So "en_US" would return "en_US", "en", "".
+class LocaleNameIterator {
+ public:
+  LocaleNameIterator(const char* locale_name, UErrorCode& status) : status_(status), has_next_(true) {
+    strcpy(locale_name_, locale_name);
+    locale_name_length_ = strlen(locale_name_);
+  }
+
+  const char* Get() {
+      return locale_name_;
+  }
+
+  bool HasNext() {
+    return has_next_;
+  }
+
+  void Up() {
+    locale_name_length_ = uloc_getParent(locale_name_, locale_name_, sizeof(locale_name_), &status_);
+    if (locale_name_length_ == 0) {
+      has_next_ = false;
+    }
+  }
+
+ private:
+  UErrorCode& status_;
+  bool has_next_;
+  char locale_name_[ULOC_FULLNAME_CAPACITY];
+  int32_t locale_name_length_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocaleNameIterator);
+};
+
+static bool getDateTimePatterns(JNIEnv* env, jobject localeData, const char* locale_name) {
+  UErrorCode status = U_ZERO_ERROR;
+  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle dateTimePatterns(ures_getByKey(gregorian.get(), "DateTimePatterns", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  setStringField(env, localeData, "fullTimeFormat", dateTimePatterns.get(), 0);
+  setStringField(env, localeData, "longTimeFormat", dateTimePatterns.get(), 1);
+  setStringField(env, localeData, "mediumTimeFormat", dateTimePatterns.get(), 2);
+  setStringField(env, localeData, "shortTimeFormat", dateTimePatterns.get(), 3);
+  setStringField(env, localeData, "fullDateFormat", dateTimePatterns.get(), 4);
+  setStringField(env, localeData, "longDateFormat", dateTimePatterns.get(), 5);
+  setStringField(env, localeData, "mediumDateFormat", dateTimePatterns.get(), 6);
+  setStringField(env, localeData, "shortDateFormat", dateTimePatterns.get(), 7);
+  return true;
+}
+
+static bool getYesterdayTodayAndTomorrow(JNIEnv* env, jobject localeData, const char* locale_name) {
+  UErrorCode status = U_ZERO_ERROR;
+  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle fields(ures_getByKey(gregorian.get(), "fields", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle day(ures_getByKey(fields.get(), "day", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  ScopedResourceBundle relative(ures_getByKey(day.get(), "relative", NULL, &status));
+  if (U_FAILURE(status)) {
+    return false;
+  }
+  // bn_BD only has a "-2" entry.
+  if (relative.hasKey("-1") && relative.hasKey("0") && relative.hasKey("1")) {
+    setStringField(env, localeData, "yesterday", relative.get(), "-1");
+    setStringField(env, localeData, "today", relative.get(), "0");
+    setStringField(env, localeData, "tomorrow", relative.get(), "1");
+    return true;
+  }
+  return false;
+}
+
 static jboolean ICU_initLocaleDataImpl(JNIEnv* env, jclass, jstring locale, jobject localeData) {
     ScopedUtfChars localeName(env, locale);
     if (localeName.c_str() == NULL) {
         return JNI_FALSE;
     }
-
-    // Get DateTimePatterns
-    UErrorCode status;
-    char currentLocale[ULOC_FULLNAME_CAPACITY];
-    int32_t localeNameLen = 0;
     if (localeName.size() >= ULOC_FULLNAME_CAPACITY) {
-        return JNI_FALSE;  // Exceed ICU defined limit of the whole locale ID.
+        return JNI_FALSE; // ICU has a fixed-length limit.
     }
-    strcpy(currentLocale, localeName.c_str());
-    do {
-        status = U_ZERO_ERROR;
-        ScopedResourceBundle root(ures_open(NULL, currentLocale, &status));
-        if (U_FAILURE(status)) {
-            if (localeNameLen == 0) {
-                break;  // No parent locale, report this error outside the loop.
-            } else {
-                status = U_ZERO_ERROR;
-                continue;  // get parent locale.
-            }
-        }
-        ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
-        if (U_FAILURE(status)) {
-            status = U_ZERO_ERROR;
-            continue;  // get parent locale.
-        }
 
-        ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
-        if (U_FAILURE(status)) {
-            status = U_ZERO_ERROR;
-            continue;  // get parent locale.
-        }
-        ScopedResourceBundle dateTimePatterns(ures_getByKey(gregorian.get(), "DateTimePatterns", NULL, &status));
-        if (U_SUCCESS(status)) {
-            setStringField(env, localeData, "fullTimeFormat", dateTimePatterns.get(), 0);
-            setStringField(env, localeData, "longTimeFormat", dateTimePatterns.get(), 1);
-            setStringField(env, localeData, "mediumTimeFormat", dateTimePatterns.get(), 2);
-            setStringField(env, localeData, "shortTimeFormat", dateTimePatterns.get(), 3);
-            setStringField(env, localeData, "fullDateFormat", dateTimePatterns.get(), 4);
-            setStringField(env, localeData, "longDateFormat", dateTimePatterns.get(), 5);
-            setStringField(env, localeData, "mediumDateFormat", dateTimePatterns.get(), 6);
-            setStringField(env, localeData, "shortDateFormat", dateTimePatterns.get(), 7);
-            break;
-        } else {
-            status = U_ZERO_ERROR;  // get parent locale.
-        }
-    } while((localeNameLen = uloc_getParent(currentLocale, currentLocale, sizeof(currentLocale), &status)) >= 0);
-    if (U_FAILURE(status)) {
-        ALOGE("Error getting ICU resource bundle: %s", u_errorName(status));
+    // Get the DateTimePatterns.
+    UErrorCode status = U_ZERO_ERROR;
+    bool foundDateTimePatterns = false;
+    for (LocaleNameIterator it(localeName.c_str(), status); it.HasNext(); it.Up()) {
+      if (getDateTimePatterns(env, localeData, it.Get())) {
+          foundDateTimePatterns = true;
+          break;
+      }
+    }
+    if (!foundDateTimePatterns) {
+        ALOGE("Couldn't find ICU DateTimePatterns for %s", localeName.c_str());
         return JNI_FALSE;
     }
 
+    // Get the "Yesterday", "Today", and "Tomorrow" strings.
+    bool foundYesterdayTodayAndTomorrow = false;
+    for (LocaleNameIterator it(localeName.c_str(), status); it.HasNext(); it.Up()) {
+      if (getYesterdayTodayAndTomorrow(env, localeData, it.Get())) {
+        foundYesterdayTodayAndTomorrow = true;
+        break;
+      }
+    }
+    if (!foundYesterdayTodayAndTomorrow) {
+      ALOGE("Couldn't find ICU yesterday/today/tomorrow for %s", localeName.c_str());
+      return JNI_FALSE;
+    }
+
     status = U_ZERO_ERROR;
     Locale localeObj = getLocale(env, locale);
-
     UniquePtr<Calendar> cal(Calendar::createInstance(localeObj, status));
     if (U_FAILURE(status)) {
         return JNI_FALSE;
     }
+
     setIntegerField(env, localeData, "firstDayOfWeek", cal->getFirstDayOfWeek());
     setIntegerField(env, localeData, "minimalDaysInFirstWeek", cal->getMinimalDaysInFirstWeek());
 
-    // Get DateFormatSymbols
+    // Get DateFormatSymbols.
     status = U_ZERO_ERROR;
     DateFormatSymbols dateFormatSym(localeObj, status);
     if (U_FAILURE(status)) {
         return JNI_FALSE;
     }
+
+    // Get AM/PM and BC/AD.
     int32_t count = 0;
-    // Get AM/PM marker
     const UnicodeString* amPmStrs = dateFormatSym.getAmPmStrings(count);
     setStringArrayField(env, localeData, "amPm", amPmStrs, count);
     const UnicodeString* erasStrs = dateFormatSym.getEras(count);
@@ -446,12 +546,18 @@
     const UnicodeString* shortMonthNames =
         dateFormatSym.getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
     setStringArrayField(env, localeData, "shortMonthNames", shortMonthNames, count);
+    const UnicodeString* tinyMonthNames =
+        dateFormatSym.getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+    setStringArrayField(env, localeData, "tinyMonthNames", tinyMonthNames, count);
     const UnicodeString* longWeekdayNames =
         dateFormatSym.getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
     setStringArrayField(env, localeData, "longWeekdayNames", longWeekdayNames, count);
     const UnicodeString* shortWeekdayNames =
         dateFormatSym.getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
     setStringArrayField(env, localeData, "shortWeekdayNames", shortWeekdayNames, count);
+    const UnicodeString* tinyWeekdayNames =
+        dateFormatSym.getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+    setStringArrayField(env, localeData, "tinyWeekdayNames", tinyWeekdayNames, count);
 
     const UnicodeString* longStandAloneMonthNames =
         dateFormatSym.getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
@@ -459,12 +565,18 @@
     const UnicodeString* shortStandAloneMonthNames =
         dateFormatSym.getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
     setStringArrayField(env, localeData, "shortStandAloneMonthNames", shortStandAloneMonthNames, count);
+    const UnicodeString* tinyStandAloneMonthNames =
+        dateFormatSym.getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+    setStringArrayField(env, localeData, "tinyStandAloneMonthNames", tinyStandAloneMonthNames, count);
     const UnicodeString* longStandAloneWeekdayNames =
         dateFormatSym.getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
     setStringArrayField(env, localeData, "longStandAloneWeekdayNames", longStandAloneWeekdayNames, count);
     const UnicodeString* shortStandAloneWeekdayNames =
         dateFormatSym.getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
     setStringArrayField(env, localeData, "shortStandAloneWeekdayNames", shortStandAloneWeekdayNames, count);
+    const UnicodeString* tinyStandAloneWeekdayNames =
+        dateFormatSym.getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+    setStringArrayField(env, localeData, "tinyStandAloneWeekdayNames", tinyStandAloneWeekdayNames, count);
 
     status = U_ZERO_ERROR;
 
@@ -543,9 +655,12 @@
     UErrorCode status = U_ZERO_ERROR;
     UEnumeration* e(ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &status));
     EnumerationCounter counter(uenum_count(e, &status));
+    if (maybeThrowIcuException(env, "uenum_count", status)) {
+        return NULL;
+    }
     EnumerationGetter getter(e, &status);
     jobject result = toStringArray16(env, &counter, &getter);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "uenum_unext", status);
     uenum_close(e);
     return result;
 }
diff --git a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
index d93c229..5865081 100644
--- a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
+++ b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
@@ -55,14 +55,14 @@
         size_t charCount = env->GetStringLength(mString);
         UErrorCode status = U_ZERO_ERROR;
         ubrk_setText(mIt, mChars, charCount, &status);
-        maybeThrowIcuException(env, status);
+        maybeThrowIcuException(env, "ubrk_setText", status);
     }
 
     BreakIteratorPeer* clone(JNIEnv* env) {
         UErrorCode status = U_ZERO_ERROR;
         jint bufferSize = U_BRK_SAFECLONE_BUFFERSIZE;
         UBreakIterator* it = ubrk_safeClone(mIt, NULL, &bufferSize, &status);
-        if (maybeThrowIcuException(env, status)) {
+        if (maybeThrowIcuException(env, "ubrk_safeClone", status)) {
             return NULL;
         }
         BreakIteratorPeer* result = new BreakIteratorPeer(it);
@@ -120,7 +120,7 @@
         return 0;
     }
     UBreakIterator* it = ubrk_open(type, localeChars.c_str(), NULL, 0, &status);
-    if (maybeThrowIcuException(env, status)) {
+    if (maybeThrowIcuException(env, "ubrk_open", status)) {
         return 0;
     }
     return (new BreakIteratorPeer(it))->toAddress();
diff --git a/luni/src/main/native/libcore_icu_NativeCollation.cpp b/luni/src/main/native/libcore_icu_NativeCollation.cpp
index 3ed49e9..32b1cc4 100644
--- a/luni/src/main/native/libcore_icu_NativeCollation.cpp
+++ b/luni/src/main/native/libcore_icu_NativeCollation.cpp
@@ -50,7 +50,7 @@
 static jint NativeCollation_getAttribute(JNIEnv* env, jclass, jint address, jint type) {
     UErrorCode status = U_ZERO_ERROR;
     jint result = ucol_getAttribute(toCollator(address), (UColAttribute) type, &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_getAttribute", status);
     return result;
 }
 
@@ -61,7 +61,7 @@
     }
     UErrorCode status = U_ZERO_ERROR;
     UCollationElements* result = ucol_openElements(toCollator(address), source.get(), source.size(), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_openElements", status);
     return static_cast<jint>(reinterpret_cast<uintptr_t>(result));
 }
 
@@ -106,7 +106,7 @@
 static jint NativeCollation_next(JNIEnv* env, jclass, jint address) {
     UErrorCode status = U_ZERO_ERROR;
     jint result = ucol_next(toCollationElements(address), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_next", status);
     return result;
 }
 
@@ -117,7 +117,7 @@
     }
     UErrorCode status = U_ZERO_ERROR;
     UCollator* c = ucol_open(localeChars.c_str(), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_open", status);
     return static_cast<jint>(reinterpret_cast<uintptr_t>(c));
 }
 
@@ -129,14 +129,14 @@
     UErrorCode status = U_ZERO_ERROR;
     UCollator* c = ucol_openRules(rules.get(), rules.size(),
             UColAttributeValue(mode), UCollationStrength(strength), NULL, &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_openRules", status);
     return static_cast<jint>(reinterpret_cast<uintptr_t>(c));
 }
 
 static jint NativeCollation_previous(JNIEnv* env, jclass, jint address) {
     UErrorCode status = U_ZERO_ERROR;
     jint result = ucol_previous(toCollationElements(address), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_previous", status);
     return result;
 }
 
@@ -148,20 +148,20 @@
     UErrorCode status = U_ZERO_ERROR;
     jint bufferSize = U_COL_SAFECLONE_BUFFERSIZE;
     UCollator* c = ucol_safeClone(toCollator(address), NULL, &bufferSize, &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_safeClone", status);
     return static_cast<jint>(reinterpret_cast<uintptr_t>(c));
 }
 
 static void NativeCollation_setAttribute(JNIEnv* env, jclass, jint address, jint type, jint value) {
     UErrorCode status = U_ZERO_ERROR;
     ucol_setAttribute(toCollator(address), (UColAttribute)type, (UColAttributeValue)value, &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_setAttribute", status);
 }
 
 static void NativeCollation_setOffset(JNIEnv* env, jclass, jint address, jint offset) {
     UErrorCode status = U_ZERO_ERROR;
     ucol_setOffset(toCollationElements(address), offset, &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_setOffset", status);
 }
 
 static void NativeCollation_setText(JNIEnv* env, jclass, jint address, jstring javaSource) {
@@ -171,7 +171,7 @@
     }
     UErrorCode status = U_ZERO_ERROR;
     ucol_setText(toCollationElements(address), source.get(), source.size(), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucol_setText", status);
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/luni/src/main/native/libcore_icu_NativeConverter.cpp b/luni/src/main/native/libcore_icu_NativeConverter.cpp
index 5b3761e..6b08ee0 100644
--- a/luni/src/main/native/libcore_icu_NativeConverter.cpp
+++ b/luni/src/main/native/libcore_icu_NativeConverter.cpp
@@ -74,7 +74,7 @@
     }
     UErrorCode status = U_ZERO_ERROR;
     UConverter* cnv = ucnv_open(converterNameChars.c_str(), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "ucnv_open", status);
     return reinterpret_cast<uintptr_t>(cnv);
 }
 
@@ -82,24 +82,36 @@
     ucnv_close(toUConverter(address));
 }
 
+static bool shouldCodecThrow(jboolean flush, UErrorCode error) {
+    if (flush) {
+        return (error != U_BUFFER_OVERFLOW_ERROR && error != U_TRUNCATED_CHAR_FOUND);
+    } else {
+        return (error != U_BUFFER_OVERFLOW_ERROR && error != U_INVALID_CHAR_FOUND && error != U_ILLEGAL_CHAR_FOUND);
+    }
+}
+
 static jint NativeConverter_encode(JNIEnv* env, jclass, jlong address,
         jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd,
         jintArray data, jboolean flush) {
 
     UConverter* cnv = toUConverter(address);
     if (cnv == NULL) {
+        maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR);
         return U_ILLEGAL_ARGUMENT_ERROR;
     }
     ScopedCharArrayRO uSource(env, source);
     if (uSource.get() == NULL) {
+        maybeThrowIcuException(env, "uSource", U_ILLEGAL_ARGUMENT_ERROR);
         return U_ILLEGAL_ARGUMENT_ERROR;
     }
     ScopedByteArrayRW uTarget(env, target);
     if (uTarget.get() == NULL) {
+        maybeThrowIcuException(env, "uTarget", U_ILLEGAL_ARGUMENT_ERROR);
         return U_ILLEGAL_ARGUMENT_ERROR;
     }
     ScopedIntArrayRW myData(env, data);
     if (myData.get() == NULL) {
+        maybeThrowIcuException(env, "myData", U_ILLEGAL_ARGUMENT_ERROR);
         return U_ILLEGAL_ARGUMENT_ERROR;
     }
 
@@ -125,6 +137,11 @@
             myData[2] = invalidUCharCount;
         }
     }
+
+    // Managed code handles some cases; throw all other errors.
+    if (shouldCodecThrow(flush, errorCode)) {
+        maybeThrowIcuException(env, "ucnv_fromUnicode", errorCode);
+    }
     return errorCode;
 }
 
@@ -134,18 +151,22 @@
 
     UConverter* cnv = toUConverter(address);
     if (cnv == NULL) {
+        maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR);
         return U_ILLEGAL_ARGUMENT_ERROR;
     }
     ScopedByteArrayRO uSource(env, source);
     if (uSource.get() == NULL) {
+        maybeThrowIcuException(env, "uSource", U_ILLEGAL_ARGUMENT_ERROR);
         return U_ILLEGAL_ARGUMENT_ERROR;
     }
     ScopedCharArrayRW uTarget(env, target);
     if (uTarget.get() == NULL) {
+        maybeThrowIcuException(env, "uTarget", U_ILLEGAL_ARGUMENT_ERROR);
         return U_ILLEGAL_ARGUMENT_ERROR;
     }
     ScopedIntArrayRW myData(env, data);
     if (myData.get() == NULL) {
+        maybeThrowIcuException(env, "myData", U_ILLEGAL_ARGUMENT_ERROR);
         return U_ILLEGAL_ARGUMENT_ERROR;
     }
 
@@ -172,6 +193,10 @@
         }
     }
 
+    // Managed code handles some cases; throw all other errors.
+    if (shouldCodecThrow(flush, errorCode)) {
+        maybeThrowIcuException(env, "ucnv_toUnicode", errorCode);
+    }
     return errorCode;
 }
 
@@ -387,11 +412,12 @@
     abort();
 }
 
-static jint NativeConverter_setCallbackEncode(JNIEnv* env, jclass, jlong address,
+static void NativeConverter_setCallbackEncode(JNIEnv* env, jclass, jlong address,
         jint onMalformedInput, jint onUnmappableInput, jbyteArray javaReplacement) {
     UConverter* cnv = toUConverter(address);
-    if (!cnv) {
-        return U_ILLEGAL_ARGUMENT_ERROR;
+    if (cnv == NULL) {
+        maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR);
+        return;
     }
 
     UConverterFromUCallback oldCallback = NULL;
@@ -409,14 +435,15 @@
 
     ScopedByteArrayRO replacementBytes(env, javaReplacement);
     if (replacementBytes.get() == NULL) {
-        return U_ILLEGAL_ARGUMENT_ERROR;
+        maybeThrowIcuException(env, "replacementBytes", U_ILLEGAL_ARGUMENT_ERROR);
+        return;
     }
     memcpy(callbackContext->replacementBytes, replacementBytes.get(), replacementBytes.size());
     callbackContext->replacementByteCount = replacementBytes.size();
 
     UErrorCode errorCode = U_ZERO_ERROR;
     ucnv_setFromUCallBack(cnv, CHARSET_ENCODER_CALLBACK, callbackContext, NULL, NULL, &errorCode);
-    return errorCode;
+    maybeThrowIcuException(env, "ucnv_setFromUCallBack", errorCode);
 }
 
 static void decoderIgnoreCallback(const void*, UConverterToUnicodeArgs*, const char*, int32_t, UConverterCallbackReason, UErrorCode* err) {
@@ -469,11 +496,12 @@
     }
 }
 
-static jint NativeConverter_setCallbackDecode(JNIEnv* env, jclass, jlong address,
+static void NativeConverter_setCallbackDecode(JNIEnv* env, jclass, jlong address,
         jint onMalformedInput, jint onUnmappableInput, jstring javaReplacement) {
     UConverter* cnv = toUConverter(address);
     if (cnv == NULL) {
-        return U_ILLEGAL_ARGUMENT_ERROR;
+        maybeThrowIcuException(env, "toConverter", U_ILLEGAL_ARGUMENT_ERROR);
+        return;
     }
 
     UConverterToUCallback oldCallback;
@@ -491,14 +519,15 @@
 
     ScopedStringChars replacement(env, javaReplacement);
     if (replacement.get() == NULL) {
-        return U_ILLEGAL_ARGUMENT_ERROR;
+        maybeThrowIcuException(env, "replacement", U_ILLEGAL_ARGUMENT_ERROR);
+        return;
     }
     u_strncpy(callbackContext->replacementChars, replacement.get(), replacement.size());
     callbackContext->replacementCharCount = replacement.size();
 
     UErrorCode errorCode = U_ZERO_ERROR;
     ucnv_setToUCallBack(cnv, CHARSET_DECODER_CALLBACK, callbackContext, NULL, NULL, &errorCode);
-    return errorCode;
+    maybeThrowIcuException(env, "ucnv_setToUCallBack", errorCode);
 }
 
 static jfloat NativeConverter_getAveCharsPerByte(JNIEnv* env, jclass, jlong handle) {
@@ -605,8 +634,8 @@
     NATIVE_METHOD(NativeConverter, openConverter, "(Ljava/lang/String;)J"),
     NATIVE_METHOD(NativeConverter, resetByteToChar, "(J)V"),
     NATIVE_METHOD(NativeConverter, resetCharToByte, "(J)V"),
-    NATIVE_METHOD(NativeConverter, setCallbackDecode, "(JIILjava/lang/String;)I"),
-    NATIVE_METHOD(NativeConverter, setCallbackEncode, "(JII[B)I"),
+    NATIVE_METHOD(NativeConverter, setCallbackDecode, "(JIILjava/lang/String;)V"),
+    NATIVE_METHOD(NativeConverter, setCallbackEncode, "(JII[B)V"),
 };
 void register_libcore_icu_NativeConverter(JNIEnv* env) {
     jniRegisterNativeMethods(env, "libcore/icu/NativeConverter", gMethods, NELEM(gMethods));
diff --git a/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp b/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp
index 1fe4055..0406094 100644
--- a/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp
+++ b/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp
@@ -122,7 +122,7 @@
     if (fmt == NULL) {
         delete symbols;
     }
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "DecimalFormat::DecimalFormat", status);
     return static_cast<jint>(reinterpret_cast<uintptr_t>(fmt));
 }
 
@@ -144,7 +144,7 @@
     UErrorCode status = U_ZERO_ERROR;
     UNumberFormatSymbol symbol = static_cast<UNumberFormatSymbol>(javaSymbol);
     unum_setSymbol(toUNumberFormat(addr), symbol, value.get(), value.size(), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "unum_setSymbol", status);
 }
 
 static void NativeDecimalFormat_setAttribute(JNIEnv*, jclass, jint addr, jint javaAttr, jint value) {
@@ -165,7 +165,7 @@
     UErrorCode status = U_ZERO_ERROR;
     UNumberFormatTextAttribute attr = static_cast<UNumberFormatTextAttribute>(javaAttr);
     unum_setTextAttribute(toUNumberFormat(addr), attr, value.get(), value.size(), &status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "unum_setTextAttribute", status);
 }
 
 static jstring NativeDecimalFormat_getTextAttribute(JNIEnv* env, jclass, jint addr, jint javaAttr) {
@@ -184,7 +184,7 @@
         chars.reset(new UChar[charCount]);
         charCount = unum_getTextAttribute(fmt, attr, chars.get(), charCount, &status);
     }
-    return maybeThrowIcuException(env, status) ? NULL : env->NewString(chars.get(), charCount);
+    return maybeThrowIcuException(env, "unum_getTextAttribute", status) ? NULL : env->NewString(chars.get(), charCount);
 }
 
 static void NativeDecimalFormat_applyPatternImpl(JNIEnv* env, jclass, jint addr, jboolean localized, jstring pattern0) {
@@ -195,12 +195,15 @@
     ScopedJavaUnicodeString pattern(env, pattern0);
     DecimalFormat* fmt = toDecimalFormat(addr);
     UErrorCode status = U_ZERO_ERROR;
+    const char* function;
     if (localized) {
+        function = "DecimalFormat::applyLocalizedPattern";
         fmt->applyLocalizedPattern(pattern.unicodeString(), status);
     } else {
+        function = "DecimalFormat::applyPattern";
         fmt->applyPattern(pattern.unicodeString(), status);
     }
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, function, status);
 }
 
 static jstring NativeDecimalFormat_toPatternImpl(JNIEnv* env, jclass, jint addr, jboolean localized) {
@@ -300,9 +303,9 @@
     fmt->parse(src.unicodeString(), res, pp);
 
     if (pp.getErrorIndex() == -1) {
-        env->CallVoidMethod(position, gPP_setIndex, (jint) pp.getIndex());
+        env->CallVoidMethod(position, gPP_setIndex, pp.getIndex());
     } else {
-        env->CallVoidMethod(position, gPP_setErrorIndex, (jint) pp.getErrorIndex());
+        env->CallVoidMethod(position, gPP_setErrorIndex, pp.getErrorIndex());
         return NULL;
     }
 
@@ -316,30 +319,18 @@
                 strncmp(data, "Inf", 3) == 0 ||
                 strncmp(data, "-Inf", 4) == 0) {
                 double resultDouble = res.getDouble(status);
-                return doubleValueOf(env, (jdouble) resultDouble);
+                return doubleValueOf(env, resultDouble);
             }
             return newBigDecimal(env, data, len);
         }
         return NULL;
     }
 
-    Formattable::Type numType = res.getType();
-        switch(numType) {
-        case Formattable::kDouble: {
-            double resultDouble = res.getDouble();
-            return doubleValueOf(env, (jdouble) resultDouble);
-        }
-        case Formattable::kLong: {
-            long resultLong = res.getLong();
-            return longValueOf(env, (jlong) resultLong);
-        }
-        case Formattable::kInt64: {
-            int64_t resultInt64 = res.getInt64();
-            return longValueOf(env, (jlong) resultInt64);
-        }
-        default: {
-            return NULL;
-        }
+    switch (res.getType()) {
+        case Formattable::kDouble: return doubleValueOf(env, res.getDouble());
+        case Formattable::kLong:   return longValueOf(env, res.getLong());
+        case Formattable::kInt64:  return longValueOf(env, res.getInt64());
+        default:                   return NULL;
     }
 }
 
diff --git a/luni/src/main/native/libcore_icu_NativeNormalizer.cpp b/luni/src/main/native/libcore_icu_NativeNormalizer.cpp
index 58f460c..693e944 100644
--- a/luni/src/main/native/libcore_icu_NativeNormalizer.cpp
+++ b/luni/src/main/native/libcore_icu_NativeNormalizer.cpp
@@ -28,7 +28,7 @@
     UErrorCode status = U_ZERO_ERROR;
     UnicodeString dst;
     Normalizer::normalize(src.unicodeString(), mode, 0, dst, status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "Normalizer::normalize", status);
     return dst.isBogus() ? NULL : env->NewString(dst.getBuffer(), dst.length());
 }
 
@@ -37,7 +37,7 @@
     UNormalizationMode mode = static_cast<UNormalizationMode>(intMode);
     UErrorCode status = U_ZERO_ERROR;
     UBool result = Normalizer::isNormalized(src.unicodeString(), mode, status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "Normalizer::isNormalized", status);
     return result;
 }
 
diff --git a/luni/src/main/native/libcore_icu_NativePluralRules.cpp b/luni/src/main/native/libcore_icu_NativePluralRules.cpp
index a7164d0..df228ff 100644
--- a/luni/src/main/native/libcore_icu_NativePluralRules.cpp
+++ b/luni/src/main/native/libcore_icu_NativePluralRules.cpp
@@ -34,7 +34,7 @@
     Locale locale = Locale::createFromName(ScopedUtfChars(env, localeName).c_str());
     UErrorCode status = U_ZERO_ERROR;
     PluralRules* result = PluralRules::forLocale(locale, status);
-    maybeThrowIcuException(env, status);
+    maybeThrowIcuException(env, "PluralRules::forLocale", status);
     return reinterpret_cast<uintptr_t>(result);
 }
 
diff --git a/luni/src/main/native/libcore_icu_TimeZones.cpp b/luni/src/main/native/libcore_icu_TimeZones.cpp
index b543238..15c18c5 100644
--- a/luni/src/main/native/libcore_icu_TimeZones.cpp
+++ b/luni/src/main/native/libcore_icu_TimeZones.cpp
@@ -43,14 +43,14 @@
     }
     UErrorCode status = U_ZERO_ERROR;
     int32_t idCount = ids->count(status);
-    if (maybeThrowIcuException(env, status)) {
+    if (maybeThrowIcuException(env, "StringEnumeration::count", status)) {
         return NULL;
     }
 
     jobjectArray result = env->NewObjectArray(idCount, JniConstants::stringClass, NULL);
     for (int32_t i = 0; i < idCount; ++i) {
         const UnicodeString* id = ids->snext(status);
-        if (maybeThrowIcuException(env, status)) {
+        if (maybeThrowIcuException(env, "StringEnumeration::snext", status)) {
             return NULL;
         }
         ScopedLocalRef<jstring> idString(env, env->NewString(id->getBuffer(), id->length()));
diff --git a/luni/src/main/native/libcore_io_Memory.cpp b/luni/src/main/native/libcore_io_Memory.cpp
index 4f1115f..fe5f12d 100644
--- a/luni/src/main/native/libcore_io_Memory.cpp
+++ b/luni/src/main/native/libcore_io_Memory.cpp
@@ -31,49 +31,114 @@
 #if defined(__arm__)
 // 32-bit ARM has load/store alignment restrictions for longs.
 #define LONG_ALIGNMENT_MASK 0x3
+#define INT_ALIGNMENT_MASK 0x0
+#define SHORT_ALIGNMENT_MASK 0x0
+#elif defined(__mips__)
+// MIPS has load/store alignment restrictions for longs, ints and shorts.
+#define LONG_ALIGNMENT_MASK 0x7
+#define INT_ALIGNMENT_MASK 0x3
+#define SHORT_ALIGNMENT_MASK 0x1
 #elif defined(__i386__)
 // x86 can load anything at any alignment.
 #define LONG_ALIGNMENT_MASK 0x0
+#define INT_ALIGNMENT_MASK 0x0
+#define SHORT_ALIGNMENT_MASK 0x0
 #else
 #error unknown load/store alignment restrictions for this architecture
 #endif
 
+// Use packed structures for access to unaligned data on targets with alignment restrictions.
+// The compiler will generate appropriate code to access these structures without
+// generating alignment exceptions.
+template <typename T> static inline T get_unaligned(const T* address) {
+    struct unaligned { T v; } __attribute__ ((packed));
+    const unaligned* p = reinterpret_cast<const unaligned*>(address);
+    return p->v;
+}
+
+template <typename T> static inline void put_unaligned(T* address, T v) {
+    struct unaligned { T v; } __attribute__ ((packed));
+    unaligned* p = reinterpret_cast<unaligned*>(address);
+    p->v = v;
+}
+
 template <typename T> static T cast(jint address) {
     return reinterpret_cast<T>(static_cast<uintptr_t>(address));
 }
 
+// Byte-swap 2 jshort values packed in a jint.
+static inline jint bswap_2x16(jint v) {
+    // v is initially ABCD
+#if defined(__mips__) && defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
+    __asm__ volatile ("wsbh %0, %0" : "+r" (v));  // v=BADC
+#else
+    v = bswap_32(v);                              // v=DCBA
+    v = (v << 16) | ((v >> 16) & 0xffff);         // v=BADC
+#endif
+    return v;
+}
+
 static inline void swapShorts(jshort* dstShorts, const jshort* srcShorts, size_t count) {
     // Do 32-bit swaps as long as possible...
     jint* dst = reinterpret_cast<jint*>(dstShorts);
     const jint* src = reinterpret_cast<const jint*>(srcShorts);
-    for (size_t i = 0; i < count / 2; ++i) {
-        jint v = *src++;                            // v=ABCD
-        v = bswap_32(v);                            // v=DCBA
-        jint v2 = (v << 16) | ((v >> 16) & 0xffff); // v=BADC
-        *dst++ = v2;
-    }
-    // ...with one last 16-bit swap if necessary.
-    if ((count % 2) != 0) {
-        jshort v = *reinterpret_cast<const jshort*>(src);
-        *reinterpret_cast<jshort*>(dst) = bswap_16(v);
+
+    if ((reinterpret_cast<uintptr_t>(dst) & INT_ALIGNMENT_MASK) == 0 &&
+        (reinterpret_cast<uintptr_t>(src) & INT_ALIGNMENT_MASK) == 0) {
+        for (size_t i = 0; i < count / 2; ++i) {
+            jint v = *src++;
+            *dst++ = bswap_2x16(v);
+        }
+        // ...with one last 16-bit swap if necessary.
+        if ((count % 2) != 0) {
+            jshort v = *reinterpret_cast<const jshort*>(src);
+            *reinterpret_cast<jshort*>(dst) = bswap_16(v);
+        }
+    } else {
+        for (size_t i = 0; i < count / 2; ++i) {
+            jint v = get_unaligned<jint>(src++);
+            put_unaligned<jint>(dst++, bswap_2x16(v));
+        }
+        if ((count % 2) != 0) {
+          jshort v = get_unaligned<jshort>(reinterpret_cast<const jshort*>(src));
+          put_unaligned<jshort>(reinterpret_cast<jshort*>(dst), bswap_16(v));
+        }
     }
 }
 
 static inline void swapInts(jint* dstInts, const jint* srcInts, size_t count) {
-    for (size_t i = 0; i < count; ++i) {
-        jint v = *srcInts++;
-        *dstInts++ = bswap_32(v);
+    if ((reinterpret_cast<uintptr_t>(dstInts) & INT_ALIGNMENT_MASK) == 0 &&
+        (reinterpret_cast<uintptr_t>(srcInts) & INT_ALIGNMENT_MASK) == 0) {
+        for (size_t i = 0; i < count; ++i) {
+            jint v = *srcInts++;
+            *dstInts++ = bswap_32(v);
+        }
+    } else {
+        for (size_t i = 0; i < count; ++i) {
+            jint v = get_unaligned<int>(srcInts++);
+            put_unaligned<jint>(dstInts++, bswap_32(v));
+        }
     }
 }
 
 static inline void swapLongs(jlong* dstLongs, const jlong* srcLongs, size_t count) {
     jint* dst = reinterpret_cast<jint*>(dstLongs);
     const jint* src = reinterpret_cast<const jint*>(srcLongs);
-    for (size_t i = 0; i < count; ++i) {
-        jint v1 = *src++;
-        jint v2 = *src++;
-        *dst++ = bswap_32(v2);
-        *dst++ = bswap_32(v1);
+    if ((reinterpret_cast<uintptr_t>(dstLongs) & INT_ALIGNMENT_MASK) == 0 &&
+        (reinterpret_cast<uintptr_t>(srcLongs) & INT_ALIGNMENT_MASK) == 0) {
+        for (size_t i = 0; i < count; ++i) {
+          jint v1 = *src++;
+          jint v2 = *src++;
+          *dst++ = bswap_32(v2);
+          *dst++ = bswap_32(v1);
+        }
+    } else {
+        for (size_t i = 0; i < count; ++i) {
+            jint v1 = get_unaligned<jint>(src++);
+            jint v2 = get_unaligned<jint>(src++);
+            put_unaligned<jint>(dst++, bswap_32(v2));
+            put_unaligned<jint>(dst++, bswap_32(v1));
+        }
     }
 }
 
@@ -226,20 +291,11 @@
 
 static jlong Memory_peekLong(JNIEnv*, jclass, jint srcAddress, jboolean swap) {
     jlong result;
+    const jlong* src = cast<const jlong*>(srcAddress);
     if ((srcAddress & LONG_ALIGNMENT_MASK) == 0) {
-        result = *cast<const jlong*>(srcAddress);
+        result = *src;
     } else {
-        // Handle unaligned memory access one byte at a time
-        const jbyte* src = cast<const jbyte*>(srcAddress);
-        jbyte* dst = reinterpret_cast<jbyte*>(&result);
-        dst[0] = src[0];
-        dst[1] = src[1];
-        dst[2] = src[2];
-        dst[3] = src[3];
-        dst[4] = src[4];
-        dst[5] = src[5];
-        dst[6] = src[6];
-        dst[7] = src[7];
+        result = get_unaligned<jlong>(src);
     }
     if (swap) {
         result = bswap_64(result);
@@ -248,23 +304,14 @@
 }
 
 static void Memory_pokeLong(JNIEnv*, jclass, jint dstAddress, jlong value, jboolean swap) {
+    jlong* dst = cast<jlong*>(dstAddress);
     if (swap) {
         value = bswap_64(value);
     }
     if ((dstAddress & LONG_ALIGNMENT_MASK) == 0) {
-        *cast<jlong*>(dstAddress) = value;
+        *dst = value;
     } else {
-        // Handle unaligned memory access one byte at a time
-        const jbyte* src = reinterpret_cast<const jbyte*>(&value);
-        jbyte* dst = cast<jbyte*>(dstAddress);
-        dst[0] = src[0];
-        dst[1] = src[1];
-        dst[2] = src[2];
-        dst[3] = src[3];
-        dst[4] = src[4];
-        dst[5] = src[5];
-        dst[6] = src[6];
-        dst[7] = src[7];
+        put_unaligned<jlong>(dst, value);
     }
 }
 
diff --git a/luni/src/main/native/libcore_io_OsConstants.cpp b/luni/src/main/native/libcore_io_OsConstants.cpp
index 622ce6d..4a719af 100644
--- a/luni/src/main/native/libcore_io_OsConstants.cpp
+++ b/luni/src/main/native/libcore_io_OsConstants.cpp
@@ -230,6 +230,7 @@
     initConstant(env, c, "O_CREAT", O_CREAT);
     initConstant(env, c, "O_EXCL", O_EXCL);
     initConstant(env, c, "O_NOCTTY", O_NOCTTY);
+    initConstant(env, c, "O_NOFOLLOW", O_NOFOLLOW);
     initConstant(env, c, "O_NONBLOCK", O_NONBLOCK);
     initConstant(env, c, "O_RDONLY", O_RDONLY);
     initConstant(env, c, "O_RDWR", O_RDWR);
@@ -275,7 +276,9 @@
     initConstant(env, c, "SIGRTMAX", SIGRTMAX);
     initConstant(env, c, "SIGRTMIN", SIGRTMIN);
     initConstant(env, c, "SIGSEGV", SIGSEGV);
+#if defined(SIGSTKFLT)
     initConstant(env, c, "SIGSTKFLT", SIGSTKFLT);
+#endif
     initConstant(env, c, "SIGSTOP", SIGSTOP);
     initConstant(env, c, "SIGSYS", SIGSYS);
     initConstant(env, c, "SIGTERM", SIGTERM);
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 30ca145..dd9b87f 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -52,6 +52,7 @@
 #include <sys/utsname.h>
 #include <sys/vfs.h> // Bionic doesn't have <sys/statvfs.h>
 #include <sys/wait.h>
+#include <termios.h>
 #include <unistd.h>
 
 #define TO_JAVA_STRING(NAME, EXP) \
@@ -67,36 +68,27 @@
 };
 
 /**
- * Used to retry syscalls that can return EINTR. This differs from TEMP_FAILURE_RETRY in that
- * it also considers the case where the reason for failure is that another thread called
- * Socket.close.
- *
- * Assumes 'JNIEnv* env' and 'jobject javaFd' (which is a java.io.FileDescriptor) are in scope.
+ * Used to retry networking system calls that can return EINTR. Unlike TEMP_FAILURE_RETRY,
+ * this also handles the case where the reason for failure is that another thread called
+ * Socket.close. This macro also throws exceptions on failure.
  *
  * Returns the result of 'exp', though a Java exception will be pending if the result is -1.
- *
- * Correct usage looks like this:
- *
- * void Posix_syscall(JNIEnv* env, jobject javaFd, ...) {
- *     ...
- *     int fd;
- *     NET_FAILURE_RETRY("syscall", syscall(fd, ...)); // Throws on error.
- * }
  */
-#define NET_FAILURE_RETRY(syscall_name, exp) ({ \
-    typeof (exp) _rc = -1; \
+#define NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
+    return_type _rc = -1; \
     do { \
         { \
-            fd = jniGetFDFromFileDescriptor(env, javaFd); \
-            AsynchronousSocketCloseMonitor monitor(fd); \
-            _rc = (exp); \
+            int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
+            AsynchronousSocketCloseMonitor _monitor(_fd); \
+            _rc = syscall_name(_fd, __VA_ARGS__); \
         } \
         if (_rc == -1) { \
-            if (jniGetFDFromFileDescriptor(env, javaFd) == -1) { \
-                jniThrowException(env, "java/net/SocketException", "Socket closed"); \
+            if (jniGetFDFromFileDescriptor(jni_env, java_fd) == -1) { \
+                jniThrowException(jni_env, "java/net/SocketException", "Socket closed"); \
                 break; \
             } else if (errno != EINTR) { \
-                throwErrnoException(env, syscall_name); \
+                /* TODO: with a format string we could show the arguments too, like strace(1). */ \
+                throwErrnoException(jni_env, # syscall_name); \
                 break; \
             } \
         } \
@@ -379,10 +371,9 @@
     sockaddr_storage ss;
     socklen_t sl = sizeof(ss);
     memset(&ss, 0, sizeof(ss));
-    int fd;
     sockaddr* peer = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
     socklen_t* peerLength = (javaInetSocketAddress != NULL) ? &sl : 0;
-    jint clientFd = NET_FAILURE_RETRY("accept", accept(fd, peer, peerLength));
+    jint clientFd = NET_FAILURE_RETRY(env, int, accept, javaFd, peer, peerLength);
     if (clientFd == -1 || !fillInetSocketAddress(env, clientFd, javaInetSocketAddress, &ss)) {
         close(clientFd);
         return NULL;
@@ -407,9 +398,9 @@
     if (!inetAddressToSockaddr(env, javaAddress, port, &ss)) {
         return;
     }
-    int fd;
     const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
-    NET_FAILURE_RETRY("bind", bind(fd, sa, sizeof(sockaddr_storage)));
+    // We don't need the return value because we'll already have thrown.
+    (void) NET_FAILURE_RETRY(env, int, bind, javaFd, sa, sizeof(sockaddr_storage));
 }
 
 static void Posix_chmod(JNIEnv* env, jobject, jstring javaPath, jint mode) {
@@ -420,6 +411,14 @@
     throwIfMinusOne(env, "chmod", TEMP_FAILURE_RETRY(chmod(path.c_str(), mode)));
 }
 
+static void Posix_chown(JNIEnv* env, jobject, jstring javaPath, jint uid, jint gid) {
+    ScopedUtfChars path(env, javaPath);
+    if (path.c_str() == NULL) {
+        return;
+    }
+    throwIfMinusOne(env, "chown", TEMP_FAILURE_RETRY(chown(path.c_str(), uid, gid)));
+}
+
 static void Posix_close(JNIEnv* env, jobject, jobject javaFd) {
     // Get the FileDescriptor's 'fd' field and clear it.
     // We need to do this before we can throw an IOException (http://b/3222087).
@@ -437,9 +436,9 @@
     if (!inetAddressToSockaddr(env, javaAddress, port, &ss)) {
         return;
     }
-    int fd;
     const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
-    NET_FAILURE_RETRY("connect", connect(fd, sa, sizeof(sockaddr_storage)));
+    // We don't need the return value because we'll already have thrown.
+    (void) NET_FAILURE_RETRY(env, int, connect, javaFd, sa, sizeof(sockaddr_storage));
 }
 
 static jobject Posix_dup(JNIEnv* env, jobject, jobject javaOldFd) {
@@ -459,6 +458,16 @@
     return toStringArray(env, environ);
 }
 
+static void Posix_fchmod(JNIEnv* env, jobject, jobject javaFd, jint mode) {
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    throwIfMinusOne(env, "fchmod", TEMP_FAILURE_RETRY(fchmod(fd, mode)));
+}
+
+static void Posix_fchown(JNIEnv* env, jobject, jobject javaFd, jint uid, jint gid) {
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    throwIfMinusOne(env, "fchown", TEMP_FAILURE_RETRY(fchown(fd, uid, gid)));
+}
+
 static jint Posix_fcntlVoid(JNIEnv* env, jobject, jobject javaFd, jint cmd) {
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
     return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd)));
@@ -791,13 +800,21 @@
 
 static jboolean Posix_isatty(JNIEnv* env, jobject, jobject javaFd) {
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
-    return TEMP_FAILURE_RETRY(isatty(fd)) == 0;
+    return TEMP_FAILURE_RETRY(isatty(fd)) == 1;
 }
 
 static void Posix_kill(JNIEnv* env, jobject, jint pid, jint sig) {
     throwIfMinusOne(env, "kill", TEMP_FAILURE_RETRY(kill(pid, sig)));
 }
 
+static void Posix_lchown(JNIEnv* env, jobject, jstring javaPath, jint uid, jint gid) {
+    ScopedUtfChars path(env, javaPath);
+    if (path.c_str() == NULL) {
+        return;
+    }
+    throwIfMinusOne(env, "lchown", TEMP_FAILURE_RETRY(lchown(path.c_str(), uid, gid)));
+}
+
 static void Posix_listen(JNIEnv* env, jobject, jobject javaFd, jint backlog) {
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
     throwIfMinusOne(env, "listen", TEMP_FAILURE_RETRY(listen(fd, backlog)));
@@ -983,10 +1000,9 @@
     sockaddr_storage ss;
     socklen_t sl = sizeof(ss);
     memset(&ss, 0, sizeof(ss));
-    int fd;
     sockaddr* from = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
     socklen_t* fromLength = (javaInetSocketAddress != NULL) ? &sl : 0;
-    jint recvCount = NET_FAILURE_RETRY("recvfrom", recvfrom(fd, bytes.get() + byteOffset, byteCount, flags, from, fromLength));
+    jint recvCount = NET_FAILURE_RETRY(env, ssize_t, recvfrom, javaFd, bytes.get() + byteOffset, byteCount, flags, from, fromLength);
     fillInetSocketAddress(env, recvCount, javaInetSocketAddress, &ss);
     return recvCount;
 }
@@ -1038,10 +1054,9 @@
     if (javaInetAddress != NULL && !inetAddressToSockaddr(env, javaInetAddress, port, &ss)) {
         return -1;
     }
-    int fd;
     const sockaddr* to = (javaInetAddress != NULL) ? reinterpret_cast<const sockaddr*>(&ss) : NULL;
     socklen_t toLength = (javaInetAddress != NULL) ? sizeof(ss) : 0;
-    return NET_FAILURE_RETRY("sendto", sendto(fd, bytes.get() + byteOffset, byteCount, flags, to, toLength));
+    return NET_FAILURE_RETRY(env, ssize_t, sendto, javaFd, bytes.get() + byteOffset, byteCount, flags, to, toLength);
 }
 
 static void Posix_setegid(JNIEnv* env, jobject, jint egid) {
@@ -1056,6 +1071,10 @@
     throwIfMinusOne(env, "setgid", TEMP_FAILURE_RETRY(setgid(gid)));
 }
 
+static jint Posix_setsid(JNIEnv* env, jobject) {
+    return throwIfMinusOne(env, "setsid", TEMP_FAILURE_RETRY(setsid()));
+}
+
 static void Posix_setsockoptByte(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jint value) {
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
     u_char byte = value;
@@ -1102,7 +1121,7 @@
     if (rc == -1 && errno == EINVAL) {
         // Maybe we're a 32-bit binary talking to a 64-bit kernel?
         // glibc doesn't automatically handle this.
-        struct GCC_HIDDEN group_req64 {
+        struct group_req64 {
             uint32_t gr_interface;
             uint32_t my_padding;
             sockaddr_storage gr_group;
@@ -1195,6 +1214,15 @@
     return result;
 }
 
+static void Posix_tcdrain(JNIEnv* env, jobject, jobject javaFd) {
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    throwIfMinusOne(env, "tcdrain", TEMP_FAILURE_RETRY(tcdrain(fd)));
+}
+
+static jint Posix_umask(JNIEnv*, jobject, jint mask) {
+    return umask(mask);
+}
+
 static jobject Posix_uname(JNIEnv* env, jobject) {
     struct utsname buf;
     if (TEMP_FAILURE_RETRY(uname(&buf)) == -1) {
@@ -1236,11 +1264,14 @@
     NATIVE_METHOD(Posix, access, "(Ljava/lang/String;I)Z"),
     NATIVE_METHOD(Posix, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
     NATIVE_METHOD(Posix, chmod, "(Ljava/lang/String;I)V"),
+    NATIVE_METHOD(Posix, chown, "(Ljava/lang/String;II)V"),
     NATIVE_METHOD(Posix, close, "(Ljava/io/FileDescriptor;)V"),
     NATIVE_METHOD(Posix, connect, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
     NATIVE_METHOD(Posix, dup, "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;"),
     NATIVE_METHOD(Posix, dup2, "(Ljava/io/FileDescriptor;I)Ljava/io/FileDescriptor;"),
     NATIVE_METHOD(Posix, environ, "()[Ljava/lang/String;"),
+    NATIVE_METHOD(Posix, fchmod, "(Ljava/io/FileDescriptor;I)V"),
+    NATIVE_METHOD(Posix, fchown, "(Ljava/io/FileDescriptor;II)V"),
     NATIVE_METHOD(Posix, fcntlVoid, "(Ljava/io/FileDescriptor;I)I"),
     NATIVE_METHOD(Posix, fcntlLong, "(Ljava/io/FileDescriptor;IJ)I"),
     NATIVE_METHOD(Posix, fcntlFlock, "(Ljava/io/FileDescriptor;ILlibcore/io/StructFlock;)I"),
@@ -1273,6 +1304,7 @@
     NATIVE_METHOD(Posix, ioctlInt, "(Ljava/io/FileDescriptor;ILlibcore/util/MutableInt;)I"),
     NATIVE_METHOD(Posix, isatty, "(Ljava/io/FileDescriptor;)Z"),
     NATIVE_METHOD(Posix, kill, "(II)V"),
+    NATIVE_METHOD(Posix, lchown, "(Ljava/lang/String;II)V"),
     NATIVE_METHOD(Posix, listen, "(Ljava/io/FileDescriptor;I)V"),
     NATIVE_METHOD(Posix, lseek, "(Ljava/io/FileDescriptor;JI)J"),
     NATIVE_METHOD(Posix, lstat, "(Ljava/lang/String;)Llibcore/io/StructStat;"),
@@ -1298,6 +1330,7 @@
     NATIVE_METHOD(Posix, setegid, "(I)V"),
     NATIVE_METHOD(Posix, seteuid, "(I)V"),
     NATIVE_METHOD(Posix, setgid, "(I)V"),
+    NATIVE_METHOD(Posix, setsid, "()I"),
     NATIVE_METHOD(Posix, setsockoptByte, "(Ljava/io/FileDescriptor;III)V"),
     NATIVE_METHOD(Posix, setsockoptIfreq, "(Ljava/io/FileDescriptor;IILjava/lang/String;)V"),
     NATIVE_METHOD(Posix, setsockoptInt, "(Ljava/io/FileDescriptor;III)V"),
@@ -1313,6 +1346,8 @@
     NATIVE_METHOD(Posix, strerror, "(I)Ljava/lang/String;"),
     NATIVE_METHOD(Posix, symlink, "(Ljava/lang/String;Ljava/lang/String;)V"),
     NATIVE_METHOD(Posix, sysconf, "(I)J"),
+    NATIVE_METHOD(Posix, tcdrain, "(Ljava/io/FileDescriptor;)V"),
+    NATIVE_METHOD(Posix, umask, "(I)I"),
     NATIVE_METHOD(Posix, uname, "()Llibcore/io/StructUtsname;"),
     NATIVE_METHOD(Posix, waitpid, "(ILlibcore/util/MutableInt;I)I"),
     NATIVE_METHOD(Posix, writeBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;II)I"),
diff --git a/luni/src/main/native/libcore_net_RawSocket.cpp b/luni/src/main/native/libcore_net_RawSocket.cpp
index 4e5059f..2e493ac 100644
--- a/luni/src/main/native/libcore_net_RawSocket.cpp
+++ b/luni/src/main/native/libcore_net_RawSocket.cpp
@@ -38,10 +38,10 @@
 #include <netinet/ip.h>
 #include <linux/udp.h>
 
-union GCC_HIDDEN sockunion {
+union sockunion {
     sockaddr sa;
     sockaddr_ll sll;
-} su;
+};
 
 /*
  * Creates a socket suitable for raw socket operations.  The socket is
@@ -61,6 +61,7 @@
     return;
   }
 
+  sockunion su;
   memset(&su, 0, sizeof(su));
   su.sll.sll_family = PF_PACKET;
   su.sll.sll_protocol = htons(protocolType);
@@ -119,6 +120,7 @@
     return 0;
   }
 
+  sockunion su;
   memset(&su, 0, sizeof(su));
   su.sll.sll_hatype = htons(1); // ARPHRD_ETHER
   su.sll.sll_halen = mac.size();
diff --git a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
index d08b7d2..ce41a51 100644
--- a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
+++ b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
@@ -30,7 +30,7 @@
 #include "unicode/unistr.h"
 
 #include <string.h>
-#include <expat.h>
+#include <libexpat/expat.h>
 
 #define BUCKET_COUNT 128
 
diff --git a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
index b9cfd19..a04bebf 100644
--- a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
+++ b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
@@ -21,9 +21,11 @@
 #define LOG_TAG "NativeCrypto"
 
 #include <algorithm>
+#include <arpa/inet.h>
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <unistd.h>
+#include <vector>
 
 #include <jni.h>
 
@@ -154,6 +156,35 @@
 };
 typedef UniquePtr<X509, X509_Delete> Unique_X509;
 
+class X509Chain {
+  public:
+    X509Chain(size_t n) : x509s_(n) {}
+
+    ~X509Chain() {
+        // TODO: C++0x auto
+        for (std::vector<X509*>::const_iterator it = x509s_.begin(); it != x509s_.end(); ++it) {
+            X509_free(*it);
+        }
+    }
+
+    X509*& operator[](size_t n) {
+        return x509s_[n];
+    }
+
+    X509* operator[](size_t n) const {
+        return x509s_[n];
+    }
+
+    X509* release(size_t i) {
+        X509* x = x509s_[i];
+        x509s_[i] = NULL;
+        return x;
+    }
+
+  private:
+    std::vector<X509*> x509s_;
+};
+
 struct X509_NAME_Delete {
     void operator()(X509_NAME* p) const {
         X509_NAME_free(p);
@@ -203,6 +234,22 @@
     ERR_remove_state(0);
 }
 
+/**
+ * Throws a BadPaddingException with the given string as a message.
+ */
+static void throwBadPaddingException(JNIEnv* env, const char* message) {
+    JNI_TRACE("throwBadPaddingException %s", message);
+    jniThrowException(env, "javax/crypto/BadPaddingException", message);
+}
+
+/**
+ * Throws a SignatureException with the given string as a message.
+ */
+static void throwSignatureException(JNIEnv* env, const char* message) {
+    JNI_TRACE("throwSignatureException %s", message);
+    jniThrowException(env, "java/security/SignatureException", message);
+}
+
 /*
  * Checks this thread's OpenSSL error queue and throws a RuntimeException if
  * necessary.
@@ -210,14 +257,30 @@
  * @return true if an exception was thrown, false if not.
  */
 static bool throwExceptionIfNecessary(JNIEnv* env, const char* location  __attribute__ ((unused))) {
-    int error = ERR_get_error();
+    const char* file;
+    int line;
+    const char* data;
+    int flags;
+    unsigned long error = ERR_get_error_line_data(&file, &line, &data, &flags);
     int result = false;
 
     if (error != 0) {
         char message[256];
         ERR_error_string_n(error, message, sizeof(message));
-        JNI_TRACE("OpenSSL error in %s %d: %s", location, error, message);
-        jniThrowRuntimeException(env, message);
+        int library = ERR_GET_LIB(error);
+        int reason = ERR_GET_REASON(error);
+        JNI_TRACE("OpenSSL error in %s error=%lx library=%x reason=%x (%s:%d): %s %s",
+                  location, error, library, reason, file, line, message,
+                  (flags & ERR_TXT_STRING) ? data : "(no data)");
+        if ((library == ERR_LIB_RSA)
+                && ((reason == RSA_R_BLOCK_TYPE_IS_NOT_01)
+                    || (reason == RSA_R_BLOCK_TYPE_IS_NOT_02))) {
+            throwBadPaddingException(env, message);
+        } else if (library == ERR_LIB_RSA && reason == RSA_R_DATA_GREATER_THAN_MOD_LEN) {
+            throwSignatureException(env, message);
+        } else {
+            jniThrowRuntimeException(env, message);
+        }
         result = true;
     }
 
@@ -577,6 +640,27 @@
     return static_cast<jint>(reinterpret_cast<uintptr_t>(e));
 }
 
+static jint NativeCrypto_ENGINE_add(JNIEnv* env, jclass, jint engineRef) {
+    ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
+    JNI_TRACE("ENGINE_add(%p)", e);
+
+    if (e == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
+        return 0;
+    }
+
+    int ret = ENGINE_add(e);
+
+    /*
+     * We tolerate errors, because the most likely error is that
+     * the ENGINE is already in the list.
+     */
+    freeOpenSslErrorState();
+
+    JNI_TRACE("ENGINE_add(%p) => %d", e, ret);
+    return ret;
+}
+
 static jint NativeCrypto_ENGINE_init(JNIEnv* env, jclass, jint engineRef) {
     ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
     JNI_TRACE("ENGINE_init(%p)", e);
@@ -1010,6 +1094,78 @@
     return static_cast<jint>(reinterpret_cast<uintptr_t>(pkey.release()));
 }
 
+static jint NativeCrypto_RSA_size(JNIEnv* env, jclass, jint pkeyRef) {
+    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+    JNI_TRACE("RSA_size(%p)", pkey);
+
+    Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
+    if (rsa.get() == NULL) {
+        jniThrowRuntimeException(env, "RSA_size failed");
+        return 0;
+    }
+
+    return static_cast<jint>(RSA_size(rsa.get()));
+}
+
+typedef int RSACryptOperation(int flen, const unsigned char* from, unsigned char* to, RSA* rsa,
+                              int padding);
+
+static jint RSA_crypt_operation(RSACryptOperation operation,
+        const char* caller __attribute__ ((unused)), JNIEnv* env, jint flen,
+        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jint pkeyRef, jint padding) {
+    EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+    JNI_TRACE("%s(%d, %p, %p, %p)", caller, flen, fromJavaBytes, toJavaBytes, pkey);
+
+    Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
+    if (rsa.get() == NULL) {
+        return -1;
+    }
+
+    ScopedByteArrayRO from(env, fromJavaBytes);
+    if (from.get() == NULL) {
+        return -1;
+    }
+
+    ScopedByteArrayRW to(env, toJavaBytes);
+    if (to.get() == NULL) {
+        return -1;
+    }
+
+    int resultSize = operation(static_cast<int>(flen),
+            reinterpret_cast<const unsigned char*>(from.get()),
+            reinterpret_cast<unsigned char*>(to.get()), rsa.get(), padding);
+    if (resultSize == -1) {
+        JNI_TRACE("%s => failed", caller);
+        throwExceptionIfNecessary(env, "RSA_crypt_operation");
+        return -1;
+    }
+
+    JNI_TRACE("%s(%d, %p, %p, %p) => %d", caller, flen, fromJavaBytes, toJavaBytes, pkey,
+              resultSize);
+    return static_cast<jint>(resultSize);
+}
+
+static jint NativeCrypto_RSA_private_encrypt(JNIEnv* env, jclass, jint flen,
+        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jint pkeyRef, jint padding) {
+    return RSA_crypt_operation(RSA_private_encrypt, __FUNCTION__,
+                               env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
+}
+static jint NativeCrypto_RSA_public_decrypt(JNIEnv* env, jclass, jint flen,
+        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jint pkeyRef, jint padding) {
+    return RSA_crypt_operation(RSA_public_decrypt, __FUNCTION__,
+                               env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
+}
+static jint NativeCrypto_RSA_public_encrypt(JNIEnv* env, jclass, jint flen,
+        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jint pkeyRef, jint padding) {
+    return RSA_crypt_operation(RSA_public_encrypt, __FUNCTION__,
+                               env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
+}
+static jint NativeCrypto_RSA_private_decrypt(JNIEnv* env, jclass, jint flen,
+        jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jint pkeyRef, jint padding) {
+    return RSA_crypt_operation(RSA_private_decrypt, __FUNCTION__,
+                               env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding);
+}
+
 /*
  * public static native byte[][] get_RSA_public_params(int);
  */
@@ -1828,6 +1984,24 @@
     return result;
 }
 
+static void NativeCrypto_RAND_bytes(JNIEnv* env, jclass, jbyteArray output) {
+    JNI_TRACE("NativeCrypto_RAND_bytes(%p)", output);
+
+    ScopedByteArrayRW outputBytes(env, output);
+    if (outputBytes.get() == NULL) {
+        return;
+    }
+
+    unsigned char* tmp = reinterpret_cast<unsigned char*>(outputBytes.get());
+    if (!RAND_bytes(tmp, outputBytes.size())) {
+        throwExceptionIfNecessary(env, "NativeCrypto_RAND_bytes");
+        JNI_TRACE("tmp=%p NativeCrypto_RAND_bytes => threw error", tmp);
+        return;
+    }
+
+    JNI_TRACE("NativeCrypto_RAND_bytes(%p) => success", output);
+}
+
 #ifdef WITH_JNI_TRACE
 /**
  * Based on example logging call back from SSL_CTX_set_info_callback man page
@@ -2364,11 +2538,19 @@
 }
 
 /**
- * Call back to ask for a client certificate
+ * Call back to ask for a client certificate. There are three possible exit codes:
+ *
+ * 1 is success. x509Out and pkeyOut should point to the correct private key and certificate.
+ * 0 is unable to find key. x509Out and pkeyOut should be NULL.
+ * -1 is error and it doesn't matter what x509Out and pkeyOut are.
  */
 static int client_cert_cb(SSL* ssl, X509** x509Out, EVP_PKEY** pkeyOut) {
     JNI_TRACE("ssl=%p client_cert_cb x509Out=%p pkeyOut=%p", ssl, x509Out, pkeyOut);
 
+    /* Clear output of key and certificate in case of early exit due to error. */
+    *x509Out = NULL;
+    *pkeyOut = NULL;
+
     AppData* appData = toAppData(ssl);
     JNIEnv* env = appData->env;
     if (env == NULL) {
@@ -2378,7 +2560,7 @@
     }
     if (env->ExceptionCheck()) {
         JNI_TRACE("ssl=%p client_cert_cb already pending exception => 0", ssl);
-        return 0;
+        return -1;
     }
     jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks;
 
@@ -2425,21 +2607,17 @@
 
     if (env->ExceptionCheck()) {
         JNI_TRACE("ssl=%p client_cert_cb exception => 0", ssl);
-        return 0;
+        return -1;
     }
 
     // Check for values set from Java
     X509*     certificate = SSL_get_certificate(ssl);
     EVP_PKEY* privatekey  = SSL_get_privatekey(ssl);
-    int result;
+    int result = 0;
     if (certificate != NULL && privatekey != NULL) {
         *x509Out = certificate;
         *pkeyOut = privatekey;
         result = 1;
-    } else {
-        *x509Out = NULL;
-        *pkeyOut = NULL;
-        result = 0;
     }
     JNI_TRACE("ssl=%p client_cert_cb => *x509=%p *pkey=%p %d", ssl, *x509Out, *pkeyOut, result);
     return result;
@@ -2779,7 +2957,7 @@
         return;
     }
 
-    Unique_X509 certificatesX509[length];
+    X509Chain certificatesX509(length);
     for (int i = 0; i < length; i++) {
         ScopedLocalRef<jbyteArray> certificate(env,
                 reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(certificates, i)));
@@ -2795,9 +2973,9 @@
             return;
         }
         const unsigned char* tmp = reinterpret_cast<const unsigned char*>(buf.get());
-        certificatesX509[i].reset(d2i_X509(NULL, &tmp, buf.size()));
+        certificatesX509[i] = d2i_X509(NULL, &tmp, buf.size());
 
-        if (certificatesX509[i].get() == NULL) {
+        if (certificatesX509[i] == NULL) {
             ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
             throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing certificate");
             SSL_clear(ssl);
@@ -2806,9 +2984,9 @@
         }
     }
 
-    int ret = SSL_use_certificate(ssl, certificatesX509[0].get());
+    int ret = SSL_use_certificate(ssl, certificatesX509[0]);
     if (ret == 1) {
-        OWNERSHIP_TRANSFERRED(certificatesX509[0]);
+        certificatesX509.release(0);
     } else {
         ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
         throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate");
@@ -2824,7 +3002,7 @@
         return;
     }
     for (int i = 1; i < length; i++) {
-        if (!sk_X509_push(chain.get(), certificatesX509[i].release())) {
+        if (!sk_X509_push(chain.get(), certificatesX509.release(i))) {
             jniThrowOutOfMemoryError(env, "Unable to push certificate");
             JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificate push error", ssl);
             return;
@@ -3186,8 +3364,10 @@
     SSL_set_mode(ssl, SSL_MODE_HANDSHAKE_CUTTHROUGH);
 
     AppData* appData = toAppData(ssl);
+    JNI_TRACE("AppData=%p", appData);
     unsigned char* npnProtocols = reinterpret_cast<unsigned char*>(appData->npnProtocolsData);
     size_t npnProtocolsLength = appData->npnProtocolsLength;
+    JNI_TRACE("npn_protocols=%p, length=%d", npnProtocols, npnProtocolsLength);
 
     int status = SSL_select_next_proto(out, outlen, in, inlen, npnProtocols, npnProtocolsLength);
     switch (status) {
@@ -3937,7 +4117,7 @@
 }
 
 /**
- * Interrupt any pending IO before closing the socket.
+ * Interrupt any pending I/O before closing the socket.
  */
 static void NativeCrypto_SSL_interrupt(
         JNIEnv* env, jclass, jint ssl_address) {
@@ -4187,6 +4367,23 @@
     const unsigned char* ucp = reinterpret_cast<const unsigned char*>(bytes.get());
     SSL_SESSION* ssl_session = d2i_SSL_SESSION(NULL, &ucp, bytes.size());
 
+    // Initialize SSL_SESSION cipher field based on cipher_id http://b/7091840
+    if (ssl_session != NULL) {
+        // based on ssl_get_prev_session
+        uint32_t cipher_id_network_order = htonl(ssl_session->cipher_id);
+        uint8_t* cipher_id_byte_pointer = reinterpret_cast<uint8_t*>(&cipher_id_network_order);
+        if (ssl_session->ssl_version >= SSL3_VERSION_MAJOR) {
+            cipher_id_byte_pointer += 2; // skip first two bytes for SSL3+
+        } else {
+            cipher_id_byte_pointer += 1; // skip first byte for SSL2
+        }
+        ssl_session->cipher = SSLv23_method()->get_cipher_by_char(cipher_id_byte_pointer);
+        JNI_TRACE("NativeCrypto_d2i_SSL_SESSION cipher_id=%lx hton=%x 0=%x 1=%x cipher=%s",
+                  ssl_session->cipher_id, cipher_id_network_order,
+                  cipher_id_byte_pointer[0], cipher_id_byte_pointer[1],
+                  SSL_CIPHER_get_name(ssl_session->cipher));
+    }
+
     JNI_TRACE("NativeCrypto_d2i_SSL_SESSION => %p", ssl_session);
     return static_cast<jint>(reinterpret_cast<uintptr_t>(ssl_session));
 }
@@ -4197,6 +4394,7 @@
     NATIVE_METHOD(NativeCrypto, clinit, "()V"),
     NATIVE_METHOD(NativeCrypto, ENGINE_load_dynamic, "()V"),
     NATIVE_METHOD(NativeCrypto, ENGINE_by_id, "(Ljava/lang/String;)I"),
+    NATIVE_METHOD(NativeCrypto, ENGINE_add, "(I)I"),
     NATIVE_METHOD(NativeCrypto, ENGINE_init, "(I)I"),
     NATIVE_METHOD(NativeCrypto, ENGINE_finish, "(I)I"),
     NATIVE_METHOD(NativeCrypto, ENGINE_free, "(I)I"),
@@ -4211,6 +4409,11 @@
     NATIVE_METHOD(NativeCrypto, i2d_PUBKEY, "(I)[B"),
     NATIVE_METHOD(NativeCrypto, d2i_PUBKEY, "([B)I"),
     NATIVE_METHOD(NativeCrypto, RSA_generate_key_ex, "(I[B)I"),
+    NATIVE_METHOD(NativeCrypto, RSA_size, "(I)I"),
+    NATIVE_METHOD(NativeCrypto, RSA_private_encrypt, "(I[B[BII)I"),
+    NATIVE_METHOD(NativeCrypto, RSA_public_decrypt, "(I[B[BII)I"),
+    NATIVE_METHOD(NativeCrypto, RSA_public_encrypt, "(I[B[BII)I"),
+    NATIVE_METHOD(NativeCrypto, RSA_private_decrypt, "(I[B[BII)I"),
     NATIVE_METHOD(NativeCrypto, get_RSA_private_params, "(I)[[B"),
     NATIVE_METHOD(NativeCrypto, get_RSA_public_params, "(I)[[B"),
     NATIVE_METHOD(NativeCrypto, DSA_generate_key, "(I[B[B[B[B)I"),
@@ -4236,6 +4439,7 @@
     NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_cleanup, "(I)V"),
     NATIVE_METHOD(NativeCrypto, RAND_seed, "([B)V"),
     NATIVE_METHOD(NativeCrypto, RAND_load_file, "(Ljava/lang/String;J)I"),
+    NATIVE_METHOD(NativeCrypto, RAND_bytes, "([B)V"),
     NATIVE_METHOD(NativeCrypto, SSL_CTX_new, "()I"),
     NATIVE_METHOD(NativeCrypto, SSL_CTX_free, "(I)V"),
     NATIVE_METHOD(NativeCrypto, SSL_CTX_set_session_id_context, "(I[B)V"),
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index b67348b..d5705a6 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -52,7 +52,6 @@
 	valueOf.cpp
 
 LOCAL_C_INCLUDES += \
-	external/expat/lib \
 	external/icu4c/common \
 	external/icu4c/i18n \
 	external/openssl/include \
diff --git a/luni/src/test/java/libcore/icu/ICUTest.java b/luni/src/test/java/libcore/icu/ICUTest.java
index 9282167..a7e732c 100644
--- a/luni/src/test/java/libcore/icu/ICUTest.java
+++ b/luni/src/test/java/libcore/icu/ICUTest.java
@@ -53,4 +53,12 @@
         assertEquals(new Locale("", "", "POSIX"), ICU.localeFromString("__POSIX"));
         assertEquals(new Locale("aa", "BB", "CC"), ICU.localeFromString("aa_BB_CC"));
     }
+
+    public void test_getScript_addLikelySubtags() throws Exception {
+        assertEquals("Latn", ICU.getScript(ICU.addLikelySubtags("en_US")));
+        assertEquals("Hebr", ICU.getScript(ICU.addLikelySubtags("he")));
+        assertEquals("Hebr", ICU.getScript(ICU.addLikelySubtags("he_IL")));
+        assertEquals("Hebr", ICU.getScript(ICU.addLikelySubtags("iw")));
+        assertEquals("Hebr", ICU.getScript(ICU.addLikelySubtags("iw_IL")));
+    }
 }
diff --git a/luni/src/test/java/libcore/icu/LocaleDataTest.java b/luni/src/test/java/libcore/icu/LocaleDataTest.java
new file mode 100644
index 0000000..e412a1d
--- /dev/null
+++ b/luni/src/test/java/libcore/icu/LocaleDataTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 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.icu;
+
+import java.util.Locale;
+
+public class LocaleDataTest extends junit.framework.TestCase {
+    public void testAll() throws Exception {
+        // Test that we can get the locale data for all known locales.
+        for (Locale l : Locale.getAvailableLocales()) {
+            LocaleData d = LocaleData.get(l);
+            System.err.println(l + " : " + d.yesterday + " " + d.today + " " + d.tomorrow);
+        }
+    }
+
+    public void test_en_US() throws Exception {
+        LocaleData l = LocaleData.get(Locale.US);
+        assertEquals("AM", l.amPm[0]);
+        assertEquals("BC", l.eras[0]);
+
+        assertEquals("January", l.longMonthNames[0]);
+        assertEquals("Jan", l.shortMonthNames[0]);
+        assertEquals("J", l.tinyMonthNames[0]);
+
+        assertEquals("January", l.longStandAloneMonthNames[0]);
+        assertEquals("Jan", l.shortStandAloneMonthNames[0]);
+        assertEquals("J", l.tinyStandAloneMonthNames[0]);
+
+        assertEquals("Sunday", l.longWeekdayNames[1]);
+        assertEquals("Sun", l.shortWeekdayNames[1]);
+        assertEquals("S", l.tinyWeekdayNames[1]);
+
+        assertEquals("Sunday", l.longStandAloneWeekdayNames[1]);
+        assertEquals("Sun", l.shortStandAloneWeekdayNames[1]);
+        assertEquals("S", l.tinyStandAloneWeekdayNames[1]);
+
+        assertEquals("Yesterday", l.yesterday);
+        assertEquals("Today", l.today);
+        assertEquals("Tomorrow", l.tomorrow);
+    }
+
+    public void test_de_DE() throws Exception {
+        LocaleData l = LocaleData.get(new Locale("de", "DE"));
+
+        assertEquals("Gestern", l.yesterday);
+        assertEquals("Heute", l.today);
+        assertEquals("Morgen", l.tomorrow);
+    }
+
+    public void test_cs_CZ() throws Exception {
+        LocaleData l = LocaleData.get(new Locale("cs", "CZ"));
+
+        assertEquals("ledna", l.longMonthNames[0]);
+        assertEquals("Led", l.shortMonthNames[0]);
+        assertEquals("1", l.tinyMonthNames[0]);
+
+        assertEquals("leden", l.longStandAloneMonthNames[0]);
+        assertEquals("1.", l.shortStandAloneMonthNames[0]);
+        assertEquals("l", l.tinyStandAloneMonthNames[0]);
+    }
+
+    public void test_ru_RU() throws Exception {
+        LocaleData l = LocaleData.get(new Locale("ru", "RU"));
+
+        assertEquals("воскресенье", l.longWeekdayNames[1]);
+        assertEquals("вс", l.shortWeekdayNames[1]);
+        assertEquals("В", l.tinyWeekdayNames[1]);
+
+        // Russian stand-alone weekday names get an initial capital.
+        assertEquals("Воскресенье", l.longStandAloneWeekdayNames[1]);
+        assertEquals("Вс", l.shortStandAloneWeekdayNames[1]);
+        assertEquals("В", l.tinyStandAloneWeekdayNames[1]);
+    }
+}
diff --git a/luni/src/test/java/libcore/io/DiskLruCacheTest.java b/luni/src/test/java/libcore/io/DiskLruCacheTest.java
index 03a6932..2796b65 100644
--- a/luni/src/test/java/libcore/io/DiskLruCacheTest.java
+++ b/luni/src/test/java/libcore/io/DiskLruCacheTest.java
@@ -349,6 +349,28 @@
         creator2.commit();
     }
 
+    public void testCreateNewEntryWithMissingFileAborts() throws Exception {
+        DiskLruCache.Editor creator = cache.edit("k1");
+        creator.set(0, "A");
+        creator.set(1, "A");
+        assertTrue(getDirtyFile("k1", 0).exists());
+        assertTrue(getDirtyFile("k1", 1).exists());
+        assertTrue(getDirtyFile("k1", 0).delete());
+        assertFalse(getDirtyFile("k1", 0).exists());
+        creator.commit();  // silently abort if file does not exist due to I/O issue
+
+        assertFalse(getCleanFile("k1", 0).exists());
+        assertFalse(getCleanFile("k1", 1).exists());
+        assertFalse(getDirtyFile("k1", 0).exists());
+        assertFalse(getDirtyFile("k1", 1).exists());
+        assertNull(cache.get("k1"));
+
+        DiskLruCache.Editor creator2 = cache.edit("k1");
+        creator2.set(0, "B");
+        creator2.set(1, "C");
+        creator2.commit();
+    }
+
     public void testRevertWithTooFewValues() throws Exception {
         DiskLruCache.Editor creator = cache.edit("k1");
         creator.set(1, "A");
@@ -805,4 +827,4 @@
         assertTrue(getCleanFile(key, 1).exists());
         snapshot.close();
     }
-}
\ No newline at end of file
+}
diff --git a/luni/src/test/java/libcore/io/MemoryTest.java b/luni/src/test/java/libcore/io/MemoryTest.java
index a533f15..9a596fb 100644
--- a/luni/src/test/java/libcore/io/MemoryTest.java
+++ b/luni/src/test/java/libcore/io/MemoryTest.java
@@ -18,6 +18,7 @@
 package libcore.io;
 
 import dalvik.system.VMRuntime;
+import java.util.Arrays;
 import junit.framework.TestCase;
 
 public class MemoryTest extends TestCase {
@@ -28,65 +29,116 @@
             swappedValues[i] = Integer.reverseBytes(values[i]);
         }
 
-        int scale = 4;
+        int scale = SizeOf.INT;
         VMRuntime runtime = VMRuntime.getRuntime();
-        byte[] array = (byte[]) runtime.newNonMovableArray(byte.class, scale * values.length);
-        int ptr = (int) runtime.addressOf(array);
+        byte[] array = (byte[]) runtime.newNonMovableArray(byte.class, scale * values.length + 1);
+        int base_ptr = (int) runtime.addressOf(array);
 
-        // Regular copy.
-        Memory.pokeIntArray(ptr, values, 0, values.length, false);
-        assertIntsEqual(values, ptr, false);
-        assertIntsEqual(swappedValues, ptr, true);
+        for (int ptr_offset = 0; ptr_offset < 2; ++ptr_offset) {
+            int ptr = base_ptr + ptr_offset; // To test aligned and unaligned accesses.
+            Arrays.fill(array, (byte) 0);
 
-        // Swapped copy.
-        Memory.pokeIntArray(ptr, values, 0, values.length, true);
-        assertIntsEqual(values, ptr, true);
-        assertIntsEqual(swappedValues, ptr, false);
+            // Regular copy.
+            Memory.pokeIntArray(ptr, values, 0, values.length, false);
+            assertIntsEqual(values, ptr, false);
+            assertIntsEqual(swappedValues, ptr, true);
 
-        // Swapped copies of slices (to ensure we test non-zero offsets).
-        for (int i = 0; i < values.length; ++i) {
-            Memory.pokeIntArray(ptr + i * scale, values, i, 1, true);
+            // Swapped copy.
+            Memory.pokeIntArray(ptr, values, 0, values.length, true);
+            assertIntsEqual(values, ptr, true);
+            assertIntsEqual(swappedValues, ptr, false);
+
+            // Swapped copies of slices (to ensure we test non-zero offsets).
+            for (int i = 0; i < values.length; ++i) {
+                Memory.pokeIntArray(ptr + i * scale, values, i, 1, true);
+            }
+            assertIntsEqual(values, ptr, true);
+            assertIntsEqual(swappedValues, ptr, false);
         }
-        assertIntsEqual(values, ptr, true);
-        assertIntsEqual(swappedValues, ptr, false);
     }
 
     private void assertIntsEqual(int[] expectedValues, int ptr, boolean swap) {
         for (int i = 0; i < expectedValues.length; ++i) {
-            assertEquals(expectedValues[i], Memory.peekInt(ptr + 4 * i, swap));
+            assertEquals(expectedValues[i], Memory.peekInt(ptr + SizeOf.INT * i, swap));
         }
     }
 
+    public void testSetLongArray() {
+        long[] values = { 0x1020304050607080L, 0xffeeddccbbaa9988L };
+        long[] swappedValues = new long[values.length];
+        for (int i = 0; i < values.length; ++i) {
+            swappedValues[i] = Long.reverseBytes(values[i]);
+        }
+
+        int scale = SizeOf.LONG;
+        VMRuntime runtime = VMRuntime.getRuntime();
+        byte[] array = (byte[]) runtime.newNonMovableArray(byte.class, scale * values.length + 1);
+        int base_ptr = (int) runtime.addressOf(array);
+
+        for (int ptr_offset = 0; ptr_offset < 2; ++ptr_offset) {
+            int ptr = base_ptr + ptr_offset; // To test aligned and unaligned accesses.
+            Arrays.fill(array, (byte) 0);
+
+            // Regular copy.
+            Memory.pokeLongArray(ptr, values, 0, values.length, false);
+            assertLongsEqual(values, ptr, false);
+            assertLongsEqual(swappedValues, ptr, true);
+
+            // Swapped copy.
+            Memory.pokeLongArray(ptr, values, 0, values.length, true);
+            assertLongsEqual(values, ptr, true);
+            assertLongsEqual(swappedValues, ptr, false);
+
+            // Swapped copies of slices (to ensure we test non-zero offsets).
+            for (int i = 0; i < values.length; ++i) {
+                Memory.pokeLongArray(ptr + i * scale, values, i, 1, true);
+            }
+            assertLongsEqual(values, ptr, true);
+            assertLongsEqual(swappedValues, ptr, false);
+        }
+    }
+
+    private void assertLongsEqual(long[] expectedValues, int ptr, boolean swap) {
+      for (int i = 0; i < expectedValues.length; ++i) {
+        assertEquals(expectedValues[i], Memory.peekLong(ptr + SizeOf.LONG * i, swap));
+      }
+    }
+
     public void testSetShortArray() {
         short[] values = { 0x0001, 0x0020, 0x0300, 0x4000 };
         short[] swappedValues = { 0x0100, 0x2000, 0x0003, 0x0040 };
 
-        int scale = 2;
+        int scale = SizeOf.SHORT;
         VMRuntime runtime = VMRuntime.getRuntime();
-        byte[] array = (byte[]) runtime.newNonMovableArray(byte.class, scale * values.length);
-        int ptr = (int) runtime.addressOf(array);
+        byte[] array = (byte[]) runtime.newNonMovableArray(byte.class, scale * values.length + 1);
+        int base_ptr = (int) runtime.addressOf(array);
 
-        // Regular copy. Memset first so we start from a known state.
-        Memory.pokeShortArray(ptr, values, 0, values.length, false);
-        assertShortsEqual(values, ptr, false);
-        assertShortsEqual(swappedValues, ptr, true);
+        for (int ptr_offset = 0; ptr_offset < 2; ++ptr_offset) {
+            int ptr = base_ptr + ptr_offset; // To test aligned and unaligned accesses.
+            Arrays.fill(array, (byte) 0);
 
-        // Swapped copy.
-        Memory.pokeShortArray(ptr, values, 0, values.length, true);
-        assertShortsEqual(values, ptr, true);
-        assertShortsEqual(swappedValues, ptr, false);
+            // Regular copy.
+            Memory.pokeShortArray(ptr, values, 0, values.length, false);
+            assertShortsEqual(values, ptr, false);
+            assertShortsEqual(swappedValues, ptr, true);
 
-        // Swapped copies of slices (to ensure we test non-zero offsets).
-        for (int i = 0; i < values.length; ++i) {
-            Memory.pokeShortArray(ptr + i * scale, values, i, 1, true);
+            // Swapped copy.
+            Memory.pokeShortArray(ptr, values, 0, values.length, true);
+            assertShortsEqual(values, ptr, true);
+            assertShortsEqual(swappedValues, ptr, false);
+
+            // Swapped copies of slices (to ensure we test non-zero offsets).
+            for (int i = 0; i < values.length; ++i) {
+                Memory.pokeShortArray(ptr + i * scale, values, i, 1, true);
+            }
+            assertShortsEqual(values, ptr, true);
+            assertShortsEqual(swappedValues, ptr, false);
         }
-        assertShortsEqual(values, ptr, true);
-        assertShortsEqual(swappedValues, ptr, false);
     }
 
     private void assertShortsEqual(short[] expectedValues, int ptr, boolean swap) {
         for (int i = 0; i < expectedValues.length; ++i) {
-            assertEquals(expectedValues[i], Memory.peekShort(ptr + 2 * i, swap));
+            assertEquals(expectedValues[i], Memory.peekShort(ptr + SizeOf.SHORT * i, swap));
         }
     }
 }
diff --git a/luni/src/test/java/libcore/io/StrictLineReaderTest.java b/luni/src/test/java/libcore/io/StrictLineReaderTest.java
new file mode 100644
index 0000000..d5d3381
--- /dev/null
+++ b/luni/src/test/java/libcore/io/StrictLineReaderTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012 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.io;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStream;
+import java.nio.charset.Charsets;
+
+public class StrictLineReaderTest extends TestCase {
+
+    public void testLineReaderConsistencyWithReadAsciiLine () {
+        try {
+            // Testing with LineReader buffer capacity 32 to check some corner cases.
+            StrictLineReader lineReader = new StrictLineReader(createTestInputStream(), 32,
+                    Charsets.US_ASCII);
+            InputStream refStream = createTestInputStream();
+            while (true) {
+                try {
+                    String refLine = Streams.readAsciiLine(refStream);
+                    try {
+                        String line = lineReader.readLine();
+                        if (!refLine.equals(line)) {
+                            fail("line (\""+line+"\") differs from expected (\""+refLine+"\").");
+                        }
+                    } catch (EOFException eof) {
+                        fail("line reader threw EOFException too early.");
+                    }
+                } catch (EOFException refEof) {
+                    try {
+                        lineReader.readLine();
+                        fail("line reader didn't throw the expected EOFException.");
+                    } catch (EOFException eof) {
+                        // OK
+                        break;
+                    }
+                }
+            }
+            refStream.close();
+            lineReader.close();
+        } catch (IOException ioe) {
+            fail("Unexpected IOException " + ioe.toString());
+        }
+    }
+
+    private InputStream createTestInputStream() {
+        return new ByteArrayInputStream((
+                /* each source lines below should represent 32 bytes, until the next comment */
+                "12 byte line\n18 byte line......\n" +
+                "pad\nline spanning two 32-byte bu" +
+                "ffers\npad......................\n" +
+                "pad\nline spanning three 32-byte " +
+                "buffers and ending with LF at th" +
+                "e end of a 32 byte buffer......\n" +
+                "pad\nLine ending with CRLF split" +
+                " at the end of a 32-byte buffer\r" +
+                "\npad...........................\n" +
+                /* end of 32-byte lines */
+                "line ending with CRLF\r\n" +
+                "this is a long line with embedded CR \r ending with CRLF and having more than " +
+                "32 characters\r\n" +
+                "unterminated line - should be dropped"
+                ).getBytes());
+    }
+}
+
diff --git a/luni/src/test/java/libcore/java/io/FileTest.java b/luni/src/test/java/libcore/java/io/FileTest.java
index 3cf621e..b2391ac 100644
--- a/luni/src/test/java/libcore/java/io/FileTest.java
+++ b/luni/src/test/java/libcore/java/io/FileTest.java
@@ -225,4 +225,45 @@
         assertTrue(new File("/").getTotalSpace() >= 0);
         assertTrue(new File("/").getUsableSpace() >= 0);
     }
+
+    public void test_mkdirs() throws Exception {
+        // Set up a directory to test in.
+        File base = createTemporaryDirectory();
+
+        // mkdirs returns true only if it _creates_ a directory.
+        // So we get false for a directory that already exists...
+        assertTrue(base.exists());
+        assertFalse(base.mkdirs());
+        // But true if we had to create something.
+        File a = new File(base, "a");
+        assertFalse(a.exists());
+        assertTrue(a.mkdirs());
+        assertTrue(a.exists());
+
+        // Test the recursive case where we need to create multiple parents.
+        File b = new File(a, "b");
+        File c = new File(b, "c");
+        File d = new File(c, "d");
+        assertTrue(a.exists());
+        assertFalse(b.exists());
+        assertFalse(c.exists());
+        assertFalse(d.exists());
+        assertTrue(d.mkdirs());
+        assertTrue(a.exists());
+        assertTrue(b.exists());
+        assertTrue(c.exists());
+        assertTrue(d.exists());
+
+        // Test the case where the 'directory' exists as a file.
+        File existsAsFile = new File(base, "existsAsFile");
+        existsAsFile.createNewFile();
+        assertTrue(existsAsFile.exists());
+        assertFalse(existsAsFile.mkdirs());
+
+        // Test the case where the parent exists as a file.
+        File badParent = new File(existsAsFile, "sub");
+        assertTrue(existsAsFile.exists());
+        assertFalse(badParent.exists());
+        assertFalse(badParent.mkdirs());
+    }
 }
diff --git a/luni/src/test/java/libcore/java/io/InterruptedStreamTest.java b/luni/src/test/java/libcore/java/io/InterruptedStreamTest.java
old mode 100644
new mode 100755
index e973b8f..e1f51bd
--- a/luni/src/test/java/libcore/java/io/InterruptedStreamTest.java
+++ b/luni/src/test/java/libcore/java/io/InterruptedStreamTest.java
@@ -28,6 +28,7 @@
 import java.net.Socket;
 import java.nio.ByteBuffer;
 import java.nio.channels.ClosedByInterruptException;
+import java.nio.channels.ClosedChannelException;
 import java.nio.channels.Pipe;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.ServerSocketChannel;
@@ -93,7 +94,7 @@
 
     public void testInterruptWritableSocketChannel() throws Exception {
         sockets = newSocketChannelPair();
-        testInterruptReadableChannel(sockets[0].getChannel());
+        testInterruptWritableChannel(sockets[0].getChannel());
     }
 
     /**
@@ -166,6 +167,7 @@
                 channel.write(ByteBuffer.allocate(BUFFER_SIZE));
             }
         } catch (ClosedByInterruptException expected) {
+        } catch (ClosedChannelException expected) {
         }
     }
 
@@ -173,6 +175,10 @@
         final Thread toInterrupt = Thread.currentThread();
         new Thread(new Runnable () {
             @Override public void run() {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException ex) {
+                }
                 toInterrupt.interrupt();
             }
         }).start();
diff --git a/luni/src/test/java/libcore/java/io/SerializationTest.java b/luni/src/test/java/libcore/java/io/SerializationTest.java
index 434dd56..d452c11 100644
--- a/luni/src/test/java/libcore/java/io/SerializationTest.java
+++ b/luni/src/test/java/libcore/java/io/SerializationTest.java
@@ -18,6 +18,8 @@
 
 import java.io.IOException;
 import java.io.InvalidClassException;
+import java.io.ObjectStreamClass;
+import java.io.ObjectStreamField;
 import java.io.Serializable;
 import junit.framework.TestCase;
 import libcore.util.SerializationTester;
@@ -26,6 +28,13 @@
 
     // http://b/4471249
     public void testSerializeFieldMadeTransient() throws Exception {
+        // Does ObjectStreamClass have the right idea?
+        ObjectStreamClass osc = ObjectStreamClass.lookup(FieldMadeTransient.class);
+        ObjectStreamField[] fields = osc.getFields();
+        assertEquals(1, fields.length);
+        assertEquals("nonTransientInt", fields[0].getName());
+        assertEquals(int.class, fields[0].getType());
+
         // this was created by serializing a FieldMadeTransient with a non-0 transientInt
         String s = "aced0005737200346c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6e54657"
                 + "374244669656c644d6164655472616e7369656e74000000000000000002000149000c7472616e736"
@@ -37,6 +46,7 @@
     static class FieldMadeTransient implements Serializable {
         private static final long serialVersionUID = 0L;
         private transient int transientInt;
+        private int nonTransientInt;
     }
 
     public void testSerialVersionUidChange() throws Exception {
diff --git a/luni/src/test/java/libcore/java/lang/IntrinsicTest.java b/luni/src/test/java/libcore/java/lang/IntrinsicTest.java
index fcf0522..6425b85 100644
--- a/luni/src/test/java/libcore/java/lang/IntrinsicTest.java
+++ b/luni/src/test/java/libcore/java/lang/IntrinsicTest.java
@@ -18,6 +18,9 @@
 
 import junit.framework.TestCase;
 
+/**
+ * Tests that all intrinsic methods are still invokable via reflection.
+ */
 public final class IntrinsicTest extends TestCase {
     public void testString_charAt() throws Exception {
         "hello".charAt(0);
@@ -60,6 +63,32 @@
         Math.class.getMethod("abs", double.class).invoke(null, 1.0);
     }
 
+    public void testStrictMath_abs() throws Exception {
+        StrictMath.abs(1);
+        StrictMath.class.getMethod("abs", int.class).invoke(null, 1);
+        StrictMath.abs(1L);
+        StrictMath.class.getMethod("abs", long.class).invoke(null, 1L);
+        StrictMath.abs(1.0f);
+        StrictMath.class.getMethod("abs", float.class).invoke(null, 1.0f);
+        StrictMath.abs(1.0);
+        StrictMath.class.getMethod("abs", double.class).invoke(null, 1.0);
+    }
+
+    public void testStrictMath_min() throws Exception {
+        StrictMath.min(1, 2);
+        StrictMath.class.getMethod("min", int.class, int.class).invoke(null, 1, 2);
+    }
+
+    public void testStrictMath_max() throws Exception {
+        StrictMath.max(1, 2);
+        StrictMath.class.getMethod("max", int.class, int.class).invoke(null, 1, 2);
+    }
+
+    public void testStrictMath_sqrt() throws Exception {
+        StrictMath.sqrt(2.0);
+        StrictMath.class.getMethod("sqrt", double.class).invoke(null, 2.0);
+    }
+
     public void testMath_min() throws Exception {
         Math.min(1, 2);
         Math.class.getMethod("min", int.class, int.class).invoke(null, 1, 2);
diff --git a/luni/src/test/java/libcore/java/lang/StringTest.java b/luni/src/test/java/libcore/java/lang/StringTest.java
index 42a7aad..99dba49 100644
--- a/luni/src/test/java/libcore/java/lang/StringTest.java
+++ b/luni/src/test/java/libcore/java/lang/StringTest.java
@@ -91,10 +91,24 @@
         }
     }
 
-    public void testStringFromCharset() {
-        Charset cs = Charset.forName("UTF-8");
-        byte[] bytes = new byte[] {(byte) 'h', (byte) 'i'};
-        assertEquals("hi", new String(bytes, cs));
+    public void testString_BII() throws Exception {
+        byte[] bytes = "xa\u0666bx".getBytes("UTF-8");
+        assertEquals("a\u0666b", new String(bytes, 1, bytes.length - 2));
+    }
+
+    public void testString_BIIString() throws Exception {
+        byte[] bytes = "xa\u0666bx".getBytes("UTF-8");
+        assertEquals("a\u0666b", new String(bytes, 1, bytes.length - 2, "UTF-8"));
+    }
+
+    public void testString_BIICharset() throws Exception {
+        byte[] bytes = "xa\u0666bx".getBytes("UTF-8");
+        assertEquals("a\u0666b", new String(bytes, 1, bytes.length - 2, Charset.forName("UTF-8")));
+    }
+
+    public void testString_BCharset() throws Exception {
+        byte[] bytes = "a\u0666b".getBytes("UTF-8");
+        assertEquals("a\u0666b", new String(bytes, Charset.forName("UTF-8")));
     }
 
     public void testStringFromCharset_MaliciousCharset() {
diff --git a/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java b/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
index 10a26fe..ef303bd 100644
--- a/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
+++ b/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
@@ -29,18 +29,42 @@
 
         FinalizationTester.induceFinalization();
         if (!finalized.get()) {
-            fail();
+            fail("object not yet finalized");
+        }
+    }
+
+    /**
+     * Test verifies that runFinalization() does not mess up objects
+     * that should be finalized later on. http://b/6907299
+     */
+    public void testInducedFinalization() throws Exception {
+        AtomicBoolean finalized1 = new AtomicBoolean();
+        AtomicBoolean finalized2 = new AtomicBoolean();
+        createFinalizableObject(finalized1);
+        createFinalizableObject(finalized2);
+        FinalizationTester.induceFinalization();
+        if (!finalized1.get() || !finalized2.get()) {
+            fail("not yet finalized: " + finalized1.get() + " " + finalized2.get());
         }
     }
 
     /** Do not inline this method; that could break non-precise GCs. See FinalizationTester. */
-    private void createFinalizableObject(final AtomicBoolean finalized) {
-        new X() {
+    private X createFinalizableObject(final AtomicBoolean finalized) {
+        X result = new X() {
             @Override protected void finalize() throws Throwable {
                 super.finalize();
                 finalized.set(true);
             }
         };
+        FinalizationTester.induceFinalization();
+        // Dance around a bit to discourage dx from realizing that 'result' is no longer live.
+        boolean wasFinalized = finalized.get();
+        if (wasFinalized) {
+            fail("finalizer called early"); // ...because 'result' is still live until we return.
+        }
+        // But we don't actually want to return 'result' because then we'd have to worry about
+        // the caller accidentally keeping it live.
+        return wasFinalized ? result : null;
     }
 
     static class X {}
diff --git a/luni/src/test/java/libcore/java/net/OldDatagramPacketTest.java b/luni/src/test/java/libcore/java/net/OldDatagramPacketTest.java
index a77a44d..8ca4067 100644
--- a/luni/src/test/java/libcore/java/net/OldDatagramPacketTest.java
+++ b/luni/src/test/java/libcore/java/net/OldDatagramPacketTest.java
@@ -21,71 +21,40 @@
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
-import tests.support.Support_PortManager;
 
 public class OldDatagramPacketTest extends junit.framework.TestCase {
 
-    DatagramPacket dp;
-
-    volatile boolean started = false;
-
-    public void test_getPort() throws IOException {
-        dp = new DatagramPacket("Hello".getBytes(), 5, InetAddress.getLocalHost(), 1000);
+    public void test_getPort() throws Exception {
+        DatagramPacket dp = new DatagramPacket("Hello".getBytes(), 5, InetAddress.getLocalHost(), 1000);
         assertEquals("Incorrect port returned", 1000, dp.getPort());
 
-        InetAddress localhost = InetAddress.getByName("localhost");
-
-        int[] ports = Support_PortManager.getNextPortsForUDP(2);
-        final int port = ports[0];
-        final Object lock = new Object();
-
+        final DatagramSocket ss = new DatagramSocket();
         Thread thread = new Thread(new Runnable() {
             public void run() {
-                DatagramSocket socket = null;
                 try {
-                    socket = new DatagramSocket(port);
-                    synchronized (lock) {
-                        started = true;
-                        lock.notifyAll();
-                    }
-                    socket.setSoTimeout(3000);
-                    DatagramPacket packet = new DatagramPacket(new byte[256],
-                            256);
-                    socket.receive(packet);
-                    socket.send(packet);
-                    socket.close();
+                    DatagramPacket packet = new DatagramPacket(new byte[256], 256);
+                    ss.setSoTimeout(3000);
+                    ss.receive(packet);
+                    ss.send(packet);
                 } catch (IOException e) {
                     System.out.println("thread exception: " + e);
-                    if (socket != null)
-                        socket.close();
                 }
             }
         });
         thread.start();
 
-        DatagramSocket socket = null;
+        DatagramSocket cs = new DatagramSocket();
         try {
-            socket = new DatagramSocket(ports[1]);
-            socket.setSoTimeout(3000);
-            DatagramPacket packet = new DatagramPacket(new byte[] { 1, 2, 3, 4,
-                    5, 6 }, 6, localhost, port);
-            synchronized (lock) {
-                try {
-                    if (!started)
-                        lock.wait();
-                } catch (InterruptedException e) {
-                    fail(e.toString());
-                }
-            }
-            socket.send(packet);
-            socket.receive(packet);
-            socket.close();
-            assertTrue("datagram received wrong port: " + packet.getPort(),
-                    packet.getPort() == port);
+            byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6 };
+            DatagramPacket packet = new DatagramPacket(bytes, 6, InetAddress.getByName("localhost"), ss.getLocalPort());
+            cs.send(packet);
+            cs.setSoTimeout(3000);
+            cs.receive(packet);
+            cs.close();
+            assertEquals(packet.getPort(), ss.getLocalPort());
         } finally {
-            if (socket != null) {
-                socket.close();
-            }
+            cs.close();
+            ss.close();
         }
     }
 
@@ -104,7 +73,7 @@
     }
 
     public void test_setData$BII() {
-        dp = new DatagramPacket("Hello".getBytes(), 5);
+        DatagramPacket dp = new DatagramPacket("Hello".getBytes(), 5);
         try {
             dp.setData(null, 2, 3);
             fail("NullPointerException was not thrown.");
@@ -113,7 +82,7 @@
     }
 
     public void test_setData$B() {
-        dp = new DatagramPacket("Hello".getBytes(), 5);
+        DatagramPacket dp = new DatagramPacket("Hello".getBytes(), 5);
         try {
             dp.setData(null);
             fail("NullPointerException was not thrown.");
diff --git a/luni/src/test/java/libcore/java/net/OldServerSocketTest.java b/luni/src/test/java/libcore/java/net/OldServerSocketTest.java
index cf35489..6518897 100644
--- a/luni/src/test/java/libcore/java/net/OldServerSocketTest.java
+++ b/luni/src/test/java/libcore/java/net/OldServerSocketTest.java
@@ -33,7 +33,6 @@
 import java.nio.channels.ServerSocketChannel;
 import java.security.Permission;
 import java.util.Properties;
-import tests.support.Support_PortManager;
 
 public class OldServerSocketTest extends OldSocketTestCase {
 
@@ -86,10 +85,9 @@
     }
 
     public void test_ConstructorII() throws IOException {
-        int freePortNumber = Support_PortManager.getNextPort();
-        s = new ServerSocket(freePortNumber, 1);
+        s = new ServerSocket(0, 1);
         s.setSoTimeout(2000);
-        startClient(freePortNumber);
+        startClient(s.getLocalPort());
         sconn = s.accept();
         sconn.close();
         s.close();
@@ -133,10 +131,9 @@
     }
 
     public void test_ConstructorI() throws Exception {
-        int portNumber = Support_PortManager.getNextPort();
-        s = new ServerSocket(portNumber);
+        s = new ServerSocket(0);
         try {
-            new ServerSocket(portNumber);
+            new ServerSocket(s.getLocalPort());
             fail("IOException was not thrown.");
         } catch(IOException ioe) {
             //expected
@@ -162,11 +159,9 @@
     }
 
     public void test_ConstructorIILjava_net_InetAddress() throws IOException {
-        int freePortNumber = Support_PortManager.getNextPort();
-
-        ServerSocket ss = new ServerSocket(freePortNumber, 10, InetAddress.getLocalHost());
+        ServerSocket ss = new ServerSocket(0, 10, InetAddress.getLocalHost());
         try {
-            new ServerSocket(freePortNumber, 10, InetAddress.getLocalHost());
+            new ServerSocket(ss.getLocalPort(), 10, InetAddress.getLocalHost());
             fail("IOException was not thrown.");
         } catch(IOException expected) {
         }
@@ -217,9 +212,7 @@
     }
 
     public void test_accept() throws IOException {
-        int portNumber = Support_PortManager.getNextPort();
-
-        ServerSocket newSocket = new ServerSocket(portNumber);
+        ServerSocket newSocket = new ServerSocket(0);
         newSocket.setSoTimeout(500);
         try {
             Socket accepted = newSocket.accept();
diff --git a/luni/src/test/java/libcore/java/net/OldURLClassLoaderTest.java b/luni/src/test/java/libcore/java/net/OldURLClassLoaderTest.java
index 2646f98..3a5608c 100644
--- a/luni/src/test/java/libcore/java/net/OldURLClassLoaderTest.java
+++ b/luni/src/test/java/libcore/java/net/OldURLClassLoaderTest.java
@@ -35,7 +35,6 @@
 import java.util.jar.Manifest;
 import org.apache.harmony.security.tests.support.TestCertUtils;
 import tests.support.Support_Configuration;
-import tests.support.Support_PortManager;
 import tests.support.Support_TestWebData;
 import tests.support.Support_TestWebServer;
 import tests.support.resource.Support_Resources;
@@ -210,13 +209,12 @@
 
     @SideEffect("Support_TestWebServer requires isolation.")
     public void test_findResourceLjava_lang_String() throws Exception {
-        int port = Support_PortManager.getNextPort();
         File tmp = File.createTempFile("test", ".txt");
 
         Support_TestWebServer server = new Support_TestWebServer();
         try {
 
-            server.initServer(port, tmp.getAbsolutePath(), "text/html");
+            int port = server.initServer(tmp.getAbsolutePath(), "text/html");
 
             URL[] urls = { new URL("http://localhost:" + port + "/") };
             ucl = new URLClassLoader(urls);
@@ -244,9 +242,8 @@
         tempFile2.deleteOnExit();
 
         Support_TestWebServer server = new Support_TestWebServer();
-        int port = Support_PortManager.getNextPort();
         try {
-            server.initServer(port, false);
+            int port = server.initServer();
 
             String tempPath1 = tempFile1.getParentFile().getAbsolutePath() + "/";
             InputStream is = getClass().getResourceAsStream(
diff --git a/luni/src/test/java/libcore/java/net/URITest.java b/luni/src/test/java/libcore/java/net/URITest.java
index b37358c..04a7d2e 100644
--- a/luni/src/test/java/libcore/java/net/URITest.java
+++ b/luni/src/test/java/libcore/java/net/URITest.java
@@ -659,5 +659,13 @@
         }
     }
 
+    // http://code.google.com/p/android/issues/detail?id=37577
+    public void testUnderscore() throws Exception {
+        URI uri = new URI("http://a_b.c.d.net/");
+        assertEquals("a_b.c.d.net", uri.getAuthority());
+        // The RFC's don't permit underscores in hostnames, and neither does URI (unlike URL).
+        assertNull(uri.getHost());
+    }
+
     // Adding a new test? Consider adding an equivalent test to URLTest.java
 }
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index 347242a..762bac4 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -24,7 +24,9 @@
 import static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_START;
 import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_INPUT_AT_END;
 import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_OUTPUT_AT_END;
+import dalvik.system.CloseGuard;
 import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -76,6 +78,7 @@
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 import junit.framework.TestCase;
+import libcore.java.lang.ref.FinalizationTester;
 import libcore.java.security.TestKeyStore;
 import libcore.javax.net.ssl.TestSSLContext;
 import libcore.net.http.HttpResponseCache;
@@ -818,6 +821,50 @@
         assertEquals(200, connection.getResponseCode());
     }
 
+    public void testDisconnectAfterOnlyResponseCodeCausesNoCloseGuardWarning() throws IOException {
+        CloseGuardGuard guard = new CloseGuardGuard();
+        try {
+            server.enqueue(new MockResponse()
+                           .setBody(gzip("ABCABCABC".getBytes("UTF-8")))
+                           .addHeader("Content-Encoding: gzip"));
+            server.play();
+
+            HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
+            assertEquals(200, connection.getResponseCode());
+            connection.disconnect();
+            connection = null;
+            assertFalse(guard.wasCloseGuardCalled());
+        } finally {
+            guard.close();
+        }
+    }
+
+    public static class CloseGuardGuard implements Closeable, CloseGuard.Reporter  {
+        private final CloseGuard.Reporter oldReporter = CloseGuard.getReporter();
+
+        private AtomicBoolean closeGuardCalled = new AtomicBoolean();
+
+        public CloseGuardGuard() {
+            CloseGuard.setReporter(this);
+        }
+
+        @Override public void report(String message, Throwable allocationSite) {
+            oldReporter.report(message, allocationSite);
+            closeGuardCalled.set(true);
+        }
+
+        public boolean wasCloseGuardCalled() {
+            FinalizationTester.induceFinalization();
+            close();
+            return closeGuardCalled.get();
+        }
+
+        @Override public void close() {
+            CloseGuard.setReporter(oldReporter);
+        }
+
+    }
+
     public void testDefaultRequestProperty() throws Exception {
         URLConnection.setDefaultRequestProperty("X-testSetDefaultRequestProperty", "A");
         assertNull(URLConnection.getDefaultRequestProperty("X-setDefaultRequestProperty"));
diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
index ced8314..962088e 100644
--- a/luni/src/test/java/libcore/java/net/URLTest.java
+++ b/luni/src/test/java/libcore/java/net/URLTest.java
@@ -686,5 +686,13 @@
         assertEquals("re f", new URL("http://host/file?query#re f").getRef());
     }
 
+    // http://code.google.com/p/android/issues/detail?id=37577
+    public void testUnderscore() throws Exception {
+        URL url = new URL("http://a_b.c.d.net/");
+        assertEquals("a_b.c.d.net", url.getAuthority());
+        // The RFC's don't permit underscores in hostnames, but URL accepts them (unlike URI).
+        assertEquals("a_b.c.d.net", url.getHost());
+    }
+
     // Adding a new test? Consider adding an equivalent test to URITest.java
 }
diff --git a/luni/src/test/java/libcore/java/nio/BufferTest.java b/luni/src/test/java/libcore/java/nio/BufferTest.java
index 06a8e94..2a895fc 100644
--- a/luni/src/test/java/libcore/java/nio/BufferTest.java
+++ b/luni/src/test/java/libcore/java/nio/BufferTest.java
@@ -675,4 +675,80 @@
         }
         assertFalse(bb.hasArray());
     }
+
+    public void testBug6085292() {
+        ByteBuffer b = ByteBuffer.allocateDirect(1);
+
+        try {
+            b.asCharBuffer().get();
+            fail();
+        } catch (BufferUnderflowException expected) {
+        }
+        try {
+            b.asCharBuffer().get(0);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+            assertTrue(expected.getMessage().contains("limit=0"));
+        }
+
+        try {
+            b.asDoubleBuffer().get();
+            fail();
+        } catch (BufferUnderflowException expected) {
+        }
+        try {
+            b.asDoubleBuffer().get(0);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+            assertTrue(expected.getMessage().contains("limit=0"));
+        }
+
+        try {
+            b.asFloatBuffer().get();
+            fail();
+        } catch (BufferUnderflowException expected) {
+        }
+        try {
+            b.asFloatBuffer().get(0);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+            assertTrue(expected.getMessage().contains("limit=0"));
+        }
+
+        try {
+            b.asIntBuffer().get();
+            fail();
+        } catch (BufferUnderflowException expected) {
+        }
+        try {
+            b.asIntBuffer().get(0);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+            assertTrue(expected.getMessage().contains("limit=0"));
+        }
+
+        try {
+            b.asLongBuffer().get();
+            fail();
+        } catch (BufferUnderflowException expected) {
+        }
+        try {
+            b.asLongBuffer().get(0);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+            assertTrue(expected.getMessage().contains("limit=0"));
+        }
+
+        try {
+            b.asShortBuffer().get();
+            fail();
+        } catch (BufferUnderflowException expected) {
+        }
+        try {
+            b.asShortBuffer().get(0);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+            assertTrue(expected.getMessage().contains("limit=0"));
+        }
+    }
 }
diff --git a/luni/src/test/java/libcore/java/nio/channels/OldServerSocketChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/OldServerSocketChannelTest.java
index fb63512..51f288a 100644
--- a/luni/src/test/java/libcore/java/nio/channels/OldServerSocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/OldServerSocketChannelTest.java
@@ -25,26 +25,17 @@
 import java.nio.channels.SocketChannel;
 import java.nio.channels.spi.SelectorProvider;
 import junit.framework.TestCase;
-import tests.support.Support_PortManager;
 
-/*
- * test for ServerSocketChannel
- */
 public class OldServerSocketChannelTest extends TestCase {
 
     private static final int TIME_UNIT = 200;
 
-    private InetSocketAddress localAddr1;
-
     private ServerSocketChannel serverChannel;
 
     private SocketChannel clientChannel;
 
     protected void setUp() throws Exception {
         super.setUp();
-        this.localAddr1 = new InetSocketAddress(
-                "127.0.0.1", Support_PortManager
-                        .getNextPort());
         this.serverChannel = ServerSocketChannel.open();
         this.clientChannel = SocketChannel.open();
     }
@@ -87,7 +78,7 @@
     public void test_accept_Block_NoConnect_interrupt() throws IOException {
         assertTrue(this.serverChannel.isBlocking());
         ServerSocket gotSocket = this.serverChannel.socket();
-        gotSocket.bind(localAddr1);
+        gotSocket.bind(null);
 
         class MyThread extends Thread {
             public String errMsg = null;
diff --git a/luni/src/test/java/libcore/java/nio/channels/OldSocketChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/OldSocketChannelTest.java
index 3987194..6560a7b 100644
--- a/luni/src/test/java/libcore/java/nio/channels/OldSocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/OldSocketChannelTest.java
@@ -35,11 +35,7 @@
 import java.nio.channels.UnsupportedAddressTypeException;
 import java.nio.channels.spi.SelectorProvider;
 import junit.framework.TestCase;
-import tests.support.Support_PortManager;
 
-/**
- * Tests for SocketChannel and its default implementation.
- */
 public class OldSocketChannelTest extends TestCase {
 
     private static final int CAPACITY_NORMAL = 200;
@@ -58,11 +54,10 @@
 
     protected void setUp() throws Exception {
         super.setUp();
-        this.localAddr1 = new InetSocketAddress("127.0.0.1",
-                Support_PortManager.getNextPort());
         this.channel1 = SocketChannel.open();
         this.channel2 = SocketChannel.open();
-        this.server1 = new ServerSocket(localAddr1.getPort());
+        this.server1 = new ServerSocket(0);
+        this.localAddr1 = (InetSocketAddress) server1.getLocalSocketAddress();
     }
 
     protected void tearDown() throws Exception {
diff --git a/luni/src/test/java/libcore/java/security/KeyStoreTest.java b/luni/src/test/java/libcore/java/security/KeyStoreTest.java
index 14d0987..15314c9 100644
--- a/luni/src/test/java/libcore/java/security/KeyStoreTest.java
+++ b/luni/src/test/java/libcore/java/security/KeyStoreTest.java
@@ -21,6 +21,7 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.security.Key;
@@ -50,7 +51,6 @@
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
 import junit.framework.TestCase;
-import libcore.io.IoUtils;
 
 public class KeyStoreTest extends TestCase {
 
@@ -207,7 +207,7 @@
         if (isReadOnly(ks)) {
             try {
                 setPrivateKey(ks);
-                fail();
+                fail(ks.toString());
             } catch (UnsupportedOperationException e) {
             }
             return;
@@ -377,7 +377,7 @@
         String type = KeyStore.getDefaultType();
         try {
             KeyStore.getInstance(null);
-            fail();
+            fail(type);
         } catch (NullPointerException expected) {
         }
 
@@ -386,12 +386,12 @@
         String providerName = StandardNames.SECURITY_PROVIDER_NAME;
         try {
             KeyStore.getInstance(null, (String)null);
-            fail();
+            fail(type);
         } catch (IllegalArgumentException expected) {
         }
         try {
             KeyStore.getInstance(null, providerName);
-            fail();
+            fail(type);
         } catch (Exception e) {
             if (e.getClass() != NullPointerException.class
                 && e.getClass() != KeyStoreException.class) {
@@ -400,7 +400,7 @@
         }
         try {
             KeyStore.getInstance(type, (String)null);
-            fail();
+            fail(type);
         } catch (IllegalArgumentException expected) {
         }
         assertNotNull(KeyStore.getInstance(type, providerName));
@@ -408,17 +408,17 @@
         Provider provider = Security.getProvider(providerName);
         try {
             KeyStore.getInstance(null, (Provider)null);
-            fail();
+            fail(type);
         } catch (IllegalArgumentException expected) {
         }
         try {
             KeyStore.getInstance(null, provider);
-            fail();
+            fail(type);
         } catch (NullPointerException expected) {
         }
         try {
             KeyStore.getInstance(type, (Provider)null);
-            fail();
+            fail(type);
         } catch (IllegalArgumentException expected) {
         }
         assertNotNull(KeyStore.getInstance(type, provider));
@@ -457,7 +457,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.getKey(null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -468,7 +468,7 @@
             // test odd inputs
             try {
                 keyStore.getKey(null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != IllegalArgumentException.class) {
@@ -477,7 +477,7 @@
             }
             try {
                 keyStore.getKey(null, PASSWORD_KEY);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != IllegalArgumentException.class
@@ -520,7 +520,7 @@
                 } else {
                     try {
                         keyStore.getKey(ALIAS_PRIVATE, null);
-                        fail();
+                        fail(keyStore.getType());
                     } catch (Exception e) {
                         if (e.getClass() != UnrecoverableKeyException.class
                             && e.getClass() != IllegalArgumentException.class) {
@@ -534,7 +534,7 @@
             } else if (isSecretKeyEnabled(keyStore)) {
                 try {
                     keyStore.getKey(ALIAS_SECRET, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (Exception e) {
                     if (e.getClass() != UnrecoverableKeyException.class
                         && e.getClass() != IllegalArgumentException.class) {
@@ -551,7 +551,7 @@
             } else {
                 try {
                     keyStore.getKey(ALIAS_PRIVATE, PASSWORD_BAD);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnrecoverableKeyException expected) {
                 }
             }
@@ -560,7 +560,7 @@
             } else if (isSecretKeyEnabled(keyStore)) {
                 try {
                     keyStore.getKey(ALIAS_SECRET, PASSWORD_BAD);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnrecoverableKeyException expected) {
                 }
             }
@@ -571,7 +571,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.getCertificateChain(null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -581,7 +581,7 @@
             // test odd inputs
             try {
                 keyStore.getCertificateChain(null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != IllegalArgumentException.class) {
@@ -610,7 +610,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.getCertificate(null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -620,7 +620,7 @@
             // test odd inputs
             try {
                 keyStore.getCertificate(null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != IllegalArgumentException.class) {
@@ -651,7 +651,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.getCreationDate(null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -664,7 +664,7 @@
             // test odd inputs
             try {
                 keyStore.getCreationDate(null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
             assertNull(keyStore.getCreationDate(""));
@@ -696,7 +696,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.setKeyEntry(null, null, null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -706,7 +706,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     keyStore.setKeyEntry(null, null, null, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -715,7 +715,7 @@
             // test odd inputs
             try {
                 keyStore.setKeyEntry(null, null, null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != KeyStoreException.class) {
@@ -724,7 +724,7 @@
             }
             try {
                 keyStore.setKeyEntry(null, null, PASSWORD_KEY, null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != KeyStoreException.class) {
@@ -736,7 +736,7 @@
                                      getPrivateKey().getPrivateKey(),
                                      PASSWORD_KEY,
                                      null);
-                fail();
+                fail(keyStore.getType());
             } catch (IllegalArgumentException expected) {
             }
         }
@@ -749,7 +749,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), PASSWORD_KEY, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -764,7 +764,7 @@
             } else {
                 try {
                     keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), PASSWORD_KEY, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (Exception e) {
                     if (e.getClass() != KeyStoreException.class
                         && e.getClass() != NullPointerException.class) {
@@ -820,7 +820,7 @@
                                          getPrivateKey().getPrivateKey(),
                                          null,
                                          getPrivateKey().getCertificateChain());
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -839,7 +839,7 @@
                                          getPrivateKey().getPrivateKey(),
                                          null,
                                          getPrivateKey().getCertificateChain());
-                    fail();
+                    fail(keyStore.getType());
                 } catch (Exception e) {
                     if (e.getClass() != UnrecoverableKeyException.class
                         && e.getClass() != IllegalArgumentException.class
@@ -855,7 +855,7 @@
                 } else {
                     try {
                         keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), null, null);
-                        fail();
+                        fail(keyStore.getType());
                     } catch (Exception e) {
                         if (e.getClass() != UnrecoverableKeyException.class
                             && e.getClass() != IllegalArgumentException.class
@@ -872,7 +872,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.setKeyEntry(null, null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -883,7 +883,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     keyStore.setKeyEntry(null, null, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -892,7 +892,7 @@
             // test odd inputs
             try {
                 keyStore.setKeyEntry(null, null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != IllegalArgumentException.class
@@ -920,7 +920,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     setPrivateKeyBytes(keyStore);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -935,7 +935,7 @@
             } else {
                 try {
                     keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey().getEncoded(), null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (KeyStoreException expected) {
                 }
             }
@@ -994,7 +994,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.setCertificateEntry(null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1005,7 +1005,7 @@
             // test odd inputs
             try {
                 keyStore.setCertificateEntry(null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != KeyStoreException.class) {
@@ -1017,7 +1017,7 @@
                 try {
                     assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
                     keyStore.setCertificateEntry(ALIAS_CERTIFICATE, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -1042,7 +1042,7 @@
             } else {
                 try {
                     keyStore.setCertificateEntry(ALIAS_CERTIFICATE, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (KeyStoreException expected) {
                 }
             }
@@ -1060,7 +1060,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     setCertificate(keyStore);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -1104,7 +1104,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.deleteEntry(null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1115,7 +1115,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     keyStore.deleteEntry(null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -1124,7 +1124,7 @@
             // test odd inputs
             try {
                 keyStore.deleteEntry(null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != KeyStoreException.class) {
@@ -1201,7 +1201,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.aliases();
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1245,7 +1245,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.containsAlias(null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1255,7 +1255,7 @@
 
             try {
                 keyStore.containsAlias(null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
 
@@ -1288,7 +1288,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.aliases();
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1330,7 +1330,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.isKeyEntry(null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1340,7 +1340,7 @@
 
             try {
                 keyStore.isKeyEntry(null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
 
@@ -1371,7 +1371,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.isCertificateEntry(null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1382,7 +1382,7 @@
             if (isCertificateEnabled(keyStore)) {
                 try {
                     keyStore.isCertificateEntry(null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (NullPointerException expected) {
                 }
             } else {
@@ -1415,7 +1415,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.getCertificateAlias(null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1479,7 +1479,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.store(null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1490,7 +1490,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     keyStore.store(out, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -1504,7 +1504,7 @@
 
             try {
                 keyStore.store(out, null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != IllegalArgumentException.class
                     && e.getClass() != NullPointerException.class) {
@@ -1520,7 +1520,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     keyStore.store(out, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException e) {
                 }
             } else if (isNullPasswordAllowed(keyStore)) {
@@ -1529,7 +1529,7 @@
             } else {
                 try {
                     keyStore.store(out, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (Exception e) {
                     if (e.getClass() != IllegalArgumentException.class
                         && e.getClass() != NullPointerException.class) {
@@ -1545,7 +1545,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     keyStore.store(out, PASSWORD_STORE);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException e) {
                 }
                 continue;
@@ -1560,7 +1560,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     keyStore.store(out, PASSWORD_STORE);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException e) {
                 }
                 continue;
@@ -1574,7 +1574,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.store(null);
-                fail();
+                fail(keyStore.getType());
             } catch (KeyStoreException expected) {
             }
         }
@@ -1583,7 +1583,7 @@
             keyStore.load(null, null);
             try {
                 keyStore.store(null);
-                fail();
+                fail(keyStore.getType());
             } catch (UnsupportedOperationException expected) {
                 assertFalse(isLoadStoreParameterSupported(keyStore));
             } catch (IllegalArgumentException expected) {
@@ -1632,7 +1632,7 @@
                             return null;
                         }
                     });
-                fail();
+                fail(keyStore.getType());
             } catch (UnsupportedOperationException expected) {
             }
         }
@@ -1642,7 +1642,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.getEntry(null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
         }
@@ -1653,12 +1653,12 @@
             // test odd inputs
             try {
                 keyStore.getEntry(null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
             try {
                 keyStore.getEntry(null, PARAM_KEY);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
             assertNull(keyStore.getEntry("", null));
@@ -1709,7 +1709,7 @@
             } else {
                 try {
                     keyStore.getEntry(ALIAS_PRIVATE, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (Exception e) {
                     if (e.getClass() != UnrecoverableKeyException.class
                         && e.getClass() != IllegalArgumentException.class) {
@@ -1722,7 +1722,7 @@
             } else if (isSecretKeyEnabled(keyStore)) {
                 try {
                     keyStore.getEntry(ALIAS_SECRET, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (Exception e) {
                     if (e.getClass() != UnrecoverableKeyException.class
                         && e.getClass() != IllegalArgumentException.class) {
@@ -1739,7 +1739,7 @@
             } else {
                 try {
                     keyStore.getEntry(ALIAS_PRIVATE, PARAM_BAD);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnrecoverableKeyException expected) {
                 }
             }
@@ -1748,19 +1748,22 @@
             } else if (isSecretKeyEnabled(keyStore)) {
                 try {
                     keyStore.getEntry(ALIAS_SECRET, PARAM_BAD);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnrecoverableKeyException expected) {
                 }
             }
         }
     }
 
+    public static class FakeProtectionParameter implements ProtectionParameter {
+    }
+
     public void test_KeyStore_setEntry() throws Exception {
         for (KeyStore keyStore : keyStores()) {
             keyStore.load(null, null);
             try {
                 keyStore.setEntry(null, null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
         }
@@ -1768,10 +1771,20 @@
         for (KeyStore keyStore : keyStores()) {
             keyStore.load(null, null);
 
+            try {
+                keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), new FakeProtectionParameter());
+                fail("Should not accept unknown ProtectionParameter");
+            } catch (KeyStoreException expected) {
+            }
+        }
+
+        for (KeyStore keyStore : keyStores()) {
+            keyStore.load(null, null);
+
             // test odd inputs
             try {
                 keyStore.setEntry(null, null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != KeyStoreException.class) {
@@ -1780,7 +1793,7 @@
             }
             try {
                 keyStore.setEntry(null, null, PARAM_KEY);
-                fail();
+                fail(keyStore.getType());
             } catch (Exception e) {
                 if (e.getClass() != NullPointerException.class
                     && e.getClass() != KeyStoreException.class) {
@@ -1789,7 +1802,7 @@
             }
             try {
                 keyStore.setEntry("", null, PARAM_KEY);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
         }
@@ -1802,7 +1815,7 @@
             if (isReadOnly(keyStore)) {
                 try {
                     keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), PARAM_KEY);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (UnsupportedOperationException expected) {
                 }
                 continue;
@@ -1817,7 +1830,7 @@
             } else {
                 try {
                     keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), PASSWORD_KEY, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (KeyStoreException expected) {
                 }
             }
@@ -1832,7 +1845,7 @@
                     keyStore.setEntry(ALIAS_CERTIFICATE,
                                       new TrustedCertificateEntry(getPrivateKey().getCertificate()),
                                       null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (KeyStoreException expected) {
                 }
             }
@@ -1846,7 +1859,7 @@
             } else {
                 try {
                     keyStore.setKeyEntry(ALIAS_UNICODE_SECRET, getSecretKey(), PASSWORD_KEY, null);
-                    fail();
+                    fail(keyStore.getType());
                 } catch (KeyStoreException expected) {
                 }
             }
@@ -1931,20 +1944,33 @@
             keyStore.load(null, null);
 
             // test with null/non-null passwords
-            try {
-                keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), null);
-                fail();
-            } catch (Exception e) {
-                if (e.getClass() != UnrecoverableKeyException.class
-                    && e.getClass() != IllegalArgumentException.class
-                    && e.getClass() != KeyStoreException.class) {
-                    throw e;
+            if (isReadOnly(keyStore)) {
+                try {
+                    keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), null);
+                    fail(keyStore.getType());
+                } catch (UnsupportedOperationException expected) {
                 }
-            }
-            if (isSecretKeyEnabled(keyStore)) {
                 try {
                     keyStore.setEntry(ALIAS_SECRET, new SecretKeyEntry(getSecretKey()), null);
-                    fail();
+                    fail(keyStore.getType());
+                } catch (UnsupportedOperationException expected) {
+                }
+                try {
+                    keyStore.setEntry(ALIAS_CERTIFICATE,
+                                      new TrustedCertificateEntry(getPrivateKey().getCertificate()),
+                                      null);
+                    fail(keyStore.getType());
+                } catch (UnsupportedOperationException expected) {
+                }
+                continue;
+            }
+            if (isNullPasswordAllowed(keyStore) || isKeyPasswordIgnored(keyStore)) {
+                keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), null);
+                assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, null));
+            } else {
+                try {
+                    keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), null);
+                    fail(keyStore.getType());
                 } catch (Exception e) {
                     if (e.getClass() != UnrecoverableKeyException.class
                         && e.getClass() != IllegalArgumentException.class
@@ -1953,15 +1979,22 @@
                     }
                 }
             }
-            if (isReadOnly(keyStore)) {
-                try {
-                    keyStore.setEntry(ALIAS_CERTIFICATE,
-                                      new TrustedCertificateEntry(getPrivateKey().getCertificate()),
-                                      PARAM_KEY);
-                    fail();
-                } catch (UnsupportedOperationException expected) {
+            if (isSecretKeyEnabled(keyStore)) {
+                if (isNullPasswordAllowed(keyStore) || isKeyPasswordIgnored(keyStore)) {
+                    keyStore.setEntry(ALIAS_SECRET, new SecretKeyEntry(getSecretKey()), null);
+                    assertSecretKey(keyStore.getKey(ALIAS_SECRET, null));
+                } else {                    
+                    try {
+                        keyStore.setEntry(ALIAS_SECRET, new SecretKeyEntry(getSecretKey()), null);
+                        fail(keyStore.getType());
+                    } catch (Exception e) {
+                        if (e.getClass() != UnrecoverableKeyException.class
+                            && e.getClass() != IllegalArgumentException.class
+                            && e.getClass() != KeyStoreException.class) {
+                            throw e;
+                        }
+                    }
                 }
-                continue;
             }
             if (isCertificateEnabled(keyStore)) {
                 if (isNullPasswordAllowed(keyStore) || isKeyPasswordIgnored(keyStore)) {
@@ -1975,7 +2008,7 @@
                                           new TrustedCertificateEntry(
                                                   getPrivateKey().getCertificate()),
                                           PARAM_KEY);
-                        fail();
+                        fail(keyStore.getType());
                     } catch (KeyStoreException expected) {
                     }
                 }
@@ -1987,7 +2020,7 @@
         for (KeyStore keyStore : keyStores()) {
             try {
                 keyStore.entryInstanceOf(null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
         }
@@ -1997,17 +2030,17 @@
 
             try {
                 keyStore.entryInstanceOf(null, null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
             try {
                 keyStore.entryInstanceOf(null, Entry.class);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
             try {
                 keyStore.entryInstanceOf("", null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
 
@@ -2082,7 +2115,7 @@
             keyStore.load(null, null);
             try {
                 Builder.newInstance(keyStore, null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
         }
@@ -2092,7 +2125,7 @@
                 Builder.newInstance(keyStore.getType(),
                                     keyStore.getProvider(),
                                     null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
         }
@@ -2103,7 +2136,7 @@
                                     null,
                                     null,
                                     null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
             try {
@@ -2111,7 +2144,7 @@
                                     keyStore.getProvider(),
                                     null,
                                     null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
         }
@@ -2121,13 +2154,13 @@
             Builder builder = Builder.newInstance(keyStore, PARAM_STORE);
             try {
                 builder.getProtectionParameter(null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
             assertEquals(keyStore, builder.getKeyStore());
             try {
                 builder.getProtectionParameter(null);
-                fail();
+                fail(keyStore.getType());
             } catch (NullPointerException expected) {
             }
             assertEquals(PARAM_STORE, builder.getProtectionParameter(""));
@@ -2143,7 +2176,7 @@
                 if (isReadOnly(keyStore)) {
                     try {
                         keyStore.store(os, PASSWORD_STORE);
-                        fail();
+                        fail(keyStore.getType());
                     } catch (UnsupportedOperationException expected) {
                     }
                     continue;
@@ -2160,7 +2193,12 @@
                 assertEquals(PARAM_STORE, builder.getProtectionParameter(""));
                 assertEqualsKeyStores(file, PASSWORD_STORE, keyStore);
             } finally {
-                IoUtils.closeQuietly(os);
+                try {
+                    if (os != null) {
+                        os.close();
+                    }
+                } catch (IOException ignored) {
+                }
                 file.delete();
             }
         }
@@ -2215,7 +2253,7 @@
     // http://b/857840: want JKS key store
     public void testDefaultKeystore() {
         String type = KeyStore.getDefaultType();
-        assertEquals("Default keystore type must be Bouncy Castle", "BKS", type);
+        assertEquals(StandardNames.KEY_STORE_ALGORITHM, type);
 
         try {
             KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
@@ -2225,7 +2263,7 @@
         }
 
         try {
-            KeyStore store = KeyStore.getInstance("BKS");
+            KeyStore store = KeyStore.getInstance(StandardNames.KEY_STORE_ALGORITHM);
             assertNotNull("Keystore must not be null", store);
         } catch (Exception ex) {
             throw new RuntimeException(ex);
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index 695908b..78608d0 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -17,14 +17,20 @@
 package libcore.java.security;
 
 import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.SecureRandomSpi;
+import java.security.Security;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.SecureRandomSpi;
 import java.security.Security;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Map;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -195,4 +201,48 @@
             }
         }
     }
+
+    /**
+     * http://code.google.com/p/android/issues/detail?id=21449
+     */
+    public void testSecureRandomImplementationOrder() {
+        Provider srp = new SRProvider();
+        try {
+            int position = Security.insertProviderAt(srp, 1); // first is one, not zero
+            assertEquals(1, position);
+            SecureRandom sr = new SecureRandom();
+            if (!sr.getAlgorithm().equals("SecureRandom1")) {
+                throw new IllegalStateException("Expected SecureRandom1");
+            }
+        } finally {
+            Security.removeProvider(srp.getName());
+        }
+    }
+
+    public static class SRProvider extends Provider {
+
+        SRProvider() {
+            super("SRProvider", 1.42, "SecureRandom Provider");
+            put("SecureRandom.SecureRandom1", SecureRandom1.class.getName());
+            put("SecureRandom.SecureRandom2", SecureRandom2.class.getName());
+            put("SecureRandom.SecureRandom3", SecureRandom3.class.getName());
+        }
+    }
+
+    public static abstract class AbstractSecureRandom extends SecureRandomSpi {
+        protected void engineSetSeed(byte[] seed) {
+            throw new UnsupportedOperationException();
+        }
+        protected void engineNextBytes(byte[] bytes) {
+            throw new UnsupportedOperationException();
+        }
+        protected byte[] engineGenerateSeed(int numBytes) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    public static class SecureRandom1 extends AbstractSecureRandom {}
+    public static class SecureRandom2 extends AbstractSecureRandom {}
+    public static class SecureRandom3 extends AbstractSecureRandom {}
+
 }
diff --git a/luni/src/test/java/libcore/java/security/SecureRandomTest.java b/luni/src/test/java/libcore/java/security/SecureRandomTest.java
new file mode 100644
index 0000000..8199120
--- /dev/null
+++ b/luni/src/test/java/libcore/java/security/SecureRandomTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.java.security;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLProvider;
+
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+public class SecureRandomTest extends TestCase {
+    private static final Class<? extends Provider> EXPECTED_PROVIDER = OpenSSLProvider.class;
+
+    private static final byte[] STATIC_SEED_BYTES = new byte[] {
+            0x0A, (byte) 0xA0, 0x01, 0x10, (byte) 0xFF, (byte) 0xF0, 0x0F
+    };
+
+    private static final long STATIC_SEED_LONG = 8506210602917522860L;
+
+    public void test_getInstance() throws Exception {
+        Provider[] providers = Security.getProviders();
+        for (Provider provider : providers) {
+            Set<Provider.Service> services = provider.getServices();
+            for (Provider.Service service : services) {
+                String type = service.getType();
+                if (!type.equals("SecureRandom")) {
+                    continue;
+                }
+
+                String algorithm = service.getAlgorithm();
+                try {
+                    SecureRandom sr1 = SecureRandom.getInstance(algorithm);
+                    assertEquals(algorithm, sr1.getAlgorithm());
+                    test_SecureRandom(sr1);
+
+                    // SecureRandom.getInstance(String, Provider)
+                    SecureRandom sr2 = SecureRandom.getInstance(algorithm, provider);
+                    assertEquals(algorithm, sr2.getAlgorithm());
+                    assertEquals(provider, sr2.getProvider());
+                    test_SecureRandom(sr2);
+
+                    // SecureRandom.getInstance(String, String)
+                    SecureRandom sr3 = SecureRandom.getInstance(algorithm, provider.getName());
+                    assertEquals(algorithm, sr3.getAlgorithm());
+                    assertEquals(provider, sr3.getProvider());
+                    test_SecureRandom(sr3);
+
+                    System.out.println("SecureRandomTest " + algorithm + " and provider "
+                            + provider.getName());
+                } catch (Exception e) {
+                    throw new Exception("Problem testing SecureRandom." + algorithm
+                            + ", provider: " + provider.getName(), e);
+                }
+            }
+        }
+    }
+
+    private void test_SecureRandom(SecureRandom sr) throws Exception {
+        byte[] out1 = new byte[20];
+        byte[] out2 = new byte[20];
+
+        sr.nextBytes(out1);
+        sr.nextBytes(out2);
+        assertFalse(Arrays.equals(out1, out2));
+
+        byte[] seed1 = sr.generateSeed(20);
+        byte[] seed2 = sr.generateSeed(20);
+        assertFalse(Arrays.equals(seed1, seed2));
+
+        sr.setSeed(STATIC_SEED_BYTES);
+        sr.nextBytes(out1);
+        sr.nextBytes(out2);
+        assertFalse(Arrays.equals(out1, out2));
+
+        sr.setSeed(STATIC_SEED_LONG);
+        sr.nextBytes(out1);
+        sr.nextBytes(out2);
+        assertFalse(Arrays.equals(out1, out2));
+    }
+
+    public void testGetCommonInstances_Success() throws Exception {
+        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
+        assertNotNull(sr);
+        assertEquals(EXPECTED_PROVIDER, sr.getProvider().getClass());
+    }
+
+    public void testNewConstructors_Success() throws Exception {
+        SecureRandom sr1 = new SecureRandom();
+        assertEquals(EXPECTED_PROVIDER, sr1.getProvider().getClass());
+        test_SecureRandom(sr1);
+
+        SecureRandom sr2 = new SecureRandom(STATIC_SEED_BYTES);
+        assertEquals(EXPECTED_PROVIDER, sr2.getProvider().getClass());
+        test_SecureRandom(sr2);
+    }
+}
diff --git a/luni/src/test/java/libcore/java/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index 2cd9982..92b5513 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -26,6 +26,7 @@
 import java.security.PublicKey;
 import java.security.Security;
 import java.security.Signature;
+import java.security.SignatureException;
 import java.security.spec.DSAPrivateKeySpec;
 import java.security.spec.DSAPublicKeySpec;
 import java.security.spec.InvalidKeySpecException;
@@ -123,9 +124,21 @@
         sig.update(DATA);
         assertTrue(sig.getAlgorithm(), sig.verify(signature));
 
-        // Calling Signature.verify a second time should not throw
-        // http://code.google.com/p/android/issues/detail?id=34933
-        sig.verify(signature);
+        /*
+         * The RI appears to clear out the input data in RawDSA while calling
+         * verify a second time.
+         */
+        if (StandardNames.IS_RI && "NONEwithDSA".equalsIgnoreCase(sig.getAlgorithm())) {
+            try {
+                sig.verify(signature);
+                fail("Expected RI to have a NONEwithDSA bug");
+            } catch (SignatureException bug) {
+            }
+        } else {
+            // Calling Signature.verify a second time should not throw
+            // http://code.google.com/p/android/issues/detail?id=34933
+            sig.verify(signature);
+        }
     }
 
     private static final byte[] PK_BYTES = hexToBytes(
@@ -326,6 +339,7 @@
         (byte) 0x39,
     });
 
+    /* Test data is: "Android.\n" */
     private static final byte[] Vector1Data = new byte[] {
         (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x2e,
         (byte) 0x0a,
@@ -550,11 +564,61 @@
         (byte) 0x02, (byte) 0xaf, (byte) 0x8f, (byte) 0x59, (byte) 0xe5, (byte) 0x67, (byte) 0x25, (byte) 0x00,
     };
 
+    /*
+     * openssl rsautl -raw -sign -inkey rsa.key | recode ../x1 | sed 's/0x/(byte) 0x/g'
+     */
+    private static final byte[] NONEwithRSA_Vector1Signature = new byte[] {
+        (byte) 0x35, (byte) 0x43, (byte) 0x38, (byte) 0x44, (byte) 0xAD, (byte) 0x3F,
+        (byte) 0x97, (byte) 0x02, (byte) 0xFB, (byte) 0x59, (byte) 0x1F, (byte) 0x4A,
+        (byte) 0x2B, (byte) 0xB9, (byte) 0x06, (byte) 0xEC, (byte) 0x66, (byte) 0xE6,
+        (byte) 0xD2, (byte) 0xC5, (byte) 0x8B, (byte) 0x7B, (byte) 0xE3, (byte) 0x18,
+        (byte) 0xBF, (byte) 0x07, (byte) 0xD6, (byte) 0x01, (byte) 0xF9, (byte) 0xD9,
+        (byte) 0x89, (byte) 0xC4, (byte) 0xDB, (byte) 0x00, (byte) 0x68, (byte) 0xFF,
+        (byte) 0x9B, (byte) 0x43, (byte) 0x90, (byte) 0xF2, (byte) 0xDB, (byte) 0x83,
+        (byte) 0xF4, (byte) 0x7E, (byte) 0xC6, (byte) 0x81, (byte) 0x01, (byte) 0x3A,
+        (byte) 0x0B, (byte) 0xE5, (byte) 0xED, (byte) 0x08, (byte) 0x73, (byte) 0x3E,
+        (byte) 0xE1, (byte) 0x3F, (byte) 0xDF, (byte) 0x1F, (byte) 0x07, (byte) 0x6D,
+        (byte) 0x22, (byte) 0x8D, (byte) 0xCC, (byte) 0x4E, (byte) 0xE3, (byte) 0x9A,
+        (byte) 0xBC, (byte) 0xCC, (byte) 0x8F, (byte) 0x9E, (byte) 0x9B, (byte) 0x02,
+        (byte) 0x48, (byte) 0x00, (byte) 0xAC, (byte) 0x9F, (byte) 0xA4, (byte) 0x8F,
+        (byte) 0x87, (byte) 0xA1, (byte) 0xA8, (byte) 0xE6, (byte) 0x9D, (byte) 0xCD,
+        (byte) 0x8B, (byte) 0x05, (byte) 0xE9, (byte) 0xD2, (byte) 0x05, (byte) 0x8D,
+        (byte) 0xC9, (byte) 0x95, (byte) 0x16, (byte) 0xD0, (byte) 0xCD, (byte) 0x43,
+        (byte) 0x25, (byte) 0x8A, (byte) 0x11, (byte) 0x46, (byte) 0xD7, (byte) 0x74,
+        (byte) 0x4C, (byte) 0xCF, (byte) 0x58, (byte) 0xF9, (byte) 0xA1, (byte) 0x30,
+        (byte) 0x84, (byte) 0x52, (byte) 0xC9, (byte) 0x01, (byte) 0x5F, (byte) 0x24,
+        (byte) 0x4C, (byte) 0xB1, (byte) 0x9F, (byte) 0x7D, (byte) 0x12, (byte) 0x38,
+        (byte) 0x27, (byte) 0x0F, (byte) 0x5E, (byte) 0xFF, (byte) 0xE0, (byte) 0x55,
+        (byte) 0x8B, (byte) 0xA3, (byte) 0xAD, (byte) 0x60, (byte) 0x35, (byte) 0x83,
+        (byte) 0x58, (byte) 0xAF, (byte) 0x99, (byte) 0xDE, (byte) 0x3F, (byte) 0x5D,
+        (byte) 0x80, (byte) 0x80, (byte) 0xFF, (byte) 0x9B, (byte) 0xDE, (byte) 0x5C,
+        (byte) 0xAB, (byte) 0x97, (byte) 0x43, (byte) 0x64, (byte) 0xD9, (byte) 0x9F,
+        (byte) 0xFB, (byte) 0x67, (byte) 0x65, (byte) 0xA5, (byte) 0x99, (byte) 0xE7,
+        (byte) 0xE6, (byte) 0xEB, (byte) 0x05, (byte) 0x95, (byte) 0xFC, (byte) 0x46,
+        (byte) 0x28, (byte) 0x4B, (byte) 0xD8, (byte) 0x8C, (byte) 0xF5, (byte) 0x0A,
+        (byte) 0xEB, (byte) 0x1F, (byte) 0x30, (byte) 0xEA, (byte) 0xE7, (byte) 0x67,
+        (byte) 0x11, (byte) 0x25, (byte) 0xF0, (byte) 0x44, (byte) 0x75, (byte) 0x74,
+        (byte) 0x94, (byte) 0x06, (byte) 0x78, (byte) 0xD0, (byte) 0x21, (byte) 0xF4,
+        (byte) 0x3F, (byte) 0xC8, (byte) 0xC4, (byte) 0x4A, (byte) 0x57, (byte) 0xBE,
+        (byte) 0x02, (byte) 0x3C, (byte) 0x93, (byte) 0xF6, (byte) 0x95, (byte) 0xFB,
+        (byte) 0xD1, (byte) 0x77, (byte) 0x8B, (byte) 0x43, (byte) 0xF0, (byte) 0xB9,
+        (byte) 0x7D, (byte) 0xE0, (byte) 0x32, (byte) 0xE1, (byte) 0x72, (byte) 0xB5,
+        (byte) 0x62, (byte) 0x3F, (byte) 0x86, (byte) 0xC3, (byte) 0xD4, (byte) 0x5F,
+        (byte) 0x5E, (byte) 0x54, (byte) 0x1B, (byte) 0x5B, (byte) 0xE6, (byte) 0x74,
+        (byte) 0xA1, (byte) 0x0B, (byte) 0xE5, (byte) 0x18, (byte) 0xD2, (byte) 0x4F,
+        (byte) 0x93, (byte) 0xF3, (byte) 0x09, (byte) 0x58, (byte) 0xCE, (byte) 0xF0,
+        (byte) 0xA3, (byte) 0x61, (byte) 0xE4, (byte) 0x6E, (byte) 0x46, (byte) 0x45,
+        (byte) 0x89, (byte) 0x50, (byte) 0xBD, (byte) 0x03, (byte) 0x3F, (byte) 0x38,
+        (byte) 0xDA, (byte) 0x5D, (byte) 0xD0, (byte) 0x1B, (byte) 0x1F, (byte) 0xB1,
+        (byte) 0xEE, (byte) 0x89, (byte) 0x59, (byte) 0xC5,
+    };
+
     public void testGetCommonInstances_Success() throws Exception {
         assertNotNull(Signature.getInstance("SHA1withRSA"));
         assertNotNull(Signature.getInstance("SHA256withRSA"));
         assertNotNull(Signature.getInstance("SHA384withRSA"));
         assertNotNull(Signature.getInstance("SHA512withRSA"));
+        assertNotNull(Signature.getInstance("NONEwithRSA"));
         assertNotNull(Signature.getInstance("MD5withRSA"));
         assertNotNull(Signature.getInstance("SHA1withDSA"));
     }
@@ -732,8 +796,7 @@
         try {
             sig.initSign(privKey);
             fail("Should throw error when private exponent is not available");
-        } catch (InvalidKeyException e) {
-            // success
+        } catch (InvalidKeyException expected) {
         }
     }
 
@@ -757,8 +820,7 @@
         try {
             sig.initSign(privKey);
             fail("Should throw error when modulus is not available");
-        } catch (InvalidKeyException e) {
-            // success
+        } catch (InvalidKeyException expected) {
         }
     }
 
@@ -781,8 +843,7 @@
         try {
             sig.initSign(privKey);
             fail("Should throw error when key is empty");
-        } catch (InvalidKeyException e) {
-            // success
+        } catch (InvalidKeyException expected) {
         }
     }
 
@@ -902,6 +963,165 @@
         assertTrue("Signature must verify correctly", sig.verify(signature));
     }
 
+    public void testSign_NONEwithRSA_Key_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+        PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Signature sig = Signature.getInstance("NONEwithRSA");
+        sig.initSign(privKey);
+        sig.update(Vector1Data);
+
+        byte[] signature = sig.sign();
+        assertNotNull("Signature must not be null", signature);
+        assertTrue("Signature should match expected",
+                Arrays.equals(signature, NONEwithRSA_Vector1Signature));
+
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        PublicKey pubKey = kf.generatePublic(pubKeySpec);
+        sig.initVerify(pubKey);
+        sig.update(Vector1Data);
+        assertTrue("Signature must verify correctly", sig.verify(signature));
+    }
+
+    public void testVerify_NONEwithRSA_Key_WrongSignature_Failure() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+        Signature sig = Signature.getInstance("NONEwithRSA");
+        sig.initVerify(pubKey);
+        sig.update(Vector1Data);
+        assertFalse("Invalid signature must not verify", sig.verify("Invalid".getBytes()));
+    }
+
+    public void testSign_NONEwithRSA_Key_DataTooLarge_Failure() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+        PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Signature sig = Signature.getInstance("NONEwithRSA");
+        sig.initSign(privKey);
+
+        final int oneTooBig = RSA_2048_modulus.bitLength() - 10;
+        for (int i = 0; i < oneTooBig; i++) {
+            sig.update((byte) i);
+        }
+
+        try {
+            sig.sign();
+            fail("Should throw exception when data is too large");
+        } catch (SignatureException expected) {
+        }
+    }
+
+    public void testSign_NONEwithRSA_Key_DataTooLarge_SingleByte_Failure() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+        PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Signature sig = Signature.getInstance("NONEwithRSA");
+        sig.initSign(privKey);
+
+        // This should make it two bytes too big.
+        final int oneTooBig = RSA_2048_modulus.bitLength() - 10;
+        for (int i = 0; i < oneTooBig; i++) {
+            sig.update((byte) i);
+        }
+
+        try {
+            sig.sign();
+            fail("Should throw exception when data is too large");
+        } catch (SignatureException expected) {
+        }
+    }
+
+    public void testVerify_NONEwithRSA_Key_DataTooLarge_Failure() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+        Signature sig = Signature.getInstance("NONEwithRSA");
+        sig.initVerify(pubKey);
+
+        // This should make it one bytes too big.
+        final int oneTooBig = RSA_2048_modulus.bitLength() + 1;
+        final byte[] vector = new byte[oneTooBig];
+        for (int i = 0; i < oneTooBig; i++) {
+            vector[i] = (byte) Vector1Data[i % Vector1Data.length];
+        }
+        sig.update(vector);
+
+        assertFalse("Should not verify when signature is too large",
+                sig.verify(NONEwithRSA_Vector1Signature));
+    }
+
+    public void testVerify_NONEwithRSA_Key_DataTooLarge_SingleByte_Failure() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+        Signature sig = Signature.getInstance("NONEwithRSA");
+        sig.initVerify(pubKey);
+
+        // This should make it twice as big as it should be.
+        final int tooBig = RSA_2048_modulus.bitLength() * 2;
+        for (int i = 0; i < tooBig; i++) {
+            sig.update((byte) Vector1Data[i % Vector1Data.length]);
+        }
+
+        assertFalse("Should not verify when signature is too large",
+                sig.verify(NONEwithRSA_Vector1Signature));
+    }
+
+    public void testVerify_NONEwithRSA_Key_SignatureTooSmall_Failure() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+        Signature sig = Signature.getInstance("NONEwithRSA");
+        sig.initVerify(pubKey);
+        sig.update(Vector1Data);
+
+        assertFalse("Invalid signature should not verify", sig.verify("Invalid sig".getBytes()));
+    }
+
+    public void testVerify_NONEwithRSA_Key_SignatureTooLarge_Failure() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+        Signature sig = Signature.getInstance("NONEwithRSA");
+        sig.initVerify(pubKey);
+        sig.update(Vector1Data);
+
+        byte[] invalidSignature = new byte[NONEwithRSA_Vector1Signature.length * 2];
+        System.arraycopy(NONEwithRSA_Vector1Signature, 0, invalidSignature, 0,
+                NONEwithRSA_Vector1Signature.length);
+        System.arraycopy(NONEwithRSA_Vector1Signature, 0, invalidSignature,
+                NONEwithRSA_Vector1Signature.length, NONEwithRSA_Vector1Signature.length);
+
+        try {
+            sig.verify(invalidSignature);
+            fail("Should throw exception when signature is too large");
+        } catch (SignatureException expected) {
+        }
+    }
+
     /*
      * These tests were generated with this DSA private key:
      *
diff --git a/luni/src/test/java/libcore/java/text/OldDateFormatTest.java b/luni/src/test/java/libcore/java/text/OldDateFormatTest.java
index 6b3885c..df388d3 100644
--- a/luni/src/test/java/libcore/java/text/OldDateFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/OldDateFormatTest.java
@@ -90,7 +90,7 @@
                     DateFormat.SHORT, DateFormat.SHORT, Locale.US);
             Date current = new Date();
             String dtf = format.format(current);
-            SimpleDateFormat sdf = new SimpleDateFormat("M/d/yy h:mm a");
+            SimpleDateFormat sdf = new SimpleDateFormat("M/d/yy h:mm a", Locale.US);
             assertTrue("Incorrect date format", sdf.format(current).equals(dtf));
         } catch (Exception e) {
             fail("Unexpected exception " + e.toString());
@@ -110,7 +110,7 @@
             StringBuffer toAppend = new StringBuffer();
             FieldPosition fp = new FieldPosition(DateFormat.YEAR_FIELD);
             StringBuffer sb = format.format(current, toAppend, fp);
-            SimpleDateFormat sdf = new SimpleDateFormat("M/d/yy h:mm a");
+            SimpleDateFormat sdf = new SimpleDateFormat("M/d/yy h:mm a", Locale.US);
             assertTrue("Incorrect date format", sdf.format(current).equals(
                     sb.toString()));
             assertTrue("Incorrect beginIndex of filed position", fp
diff --git a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
index c6296ff..cd54d1e 100644
--- a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
@@ -51,6 +51,7 @@
     // The RI fails this test because this is an ICU-compatible Android extension.
     // Necessary for correct localization in various languages (http://b/2633414).
     public void testStandAloneNames() throws Exception {
+        TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
         Locale en = Locale.ENGLISH;
         Locale pl = new Locale("pl");
         Locale ru = new Locale("ru");
@@ -77,7 +78,7 @@
     }
 
     public void test2038() {
-        SimpleDateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy");
+        SimpleDateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", Locale.US);
         format.setTimeZone(TimeZone.getTimeZone("UTC"));
 
         assertEquals("Sun Nov 24 17:31:44 1833",
@@ -175,14 +176,14 @@
      * longer use their DST zone but we should continue to parse it properly.
      */
     public void testObsoleteDstZoneName() throws Exception {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz");
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz", Locale.US);
         Date normal = format.parse("1970-01-01T00:00 EET");
         Date dst = format.parse("1970-01-01T00:00 EEST");
         assertEquals(60 * 60 * 1000, normal.getTime() - dst.getTime());
     }
 
     public void testDstZoneNameWithNonDstTimestamp() throws Exception {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz");
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz", Locale.US);
         Calendar calendar = new GregorianCalendar(AMERICA_LOS_ANGELES);
         calendar.setTime(format.parse("2011-06-21T10:00 Pacific Standard Time")); // 18:00 GMT-8
         assertEquals(11, calendar.get(Calendar.HOUR_OF_DAY)); // 18:00 GMT-7
@@ -190,7 +191,7 @@
     }
 
     public void testNonDstZoneNameWithDstTimestamp() throws Exception {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz");
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz", Locale.US);
         Calendar calendar = new GregorianCalendar(AMERICA_LOS_ANGELES);
         calendar.setTime(format.parse("2010-12-21T10:00 Pacific Daylight Time")); // 17:00 GMT-7
         assertEquals(9, calendar.get(Calendar.HOUR_OF_DAY)); // 17:00 GMT-8
@@ -199,7 +200,7 @@
 
     // http://b/4723412
     public void testDstZoneWithNonDstTimestampForNonHourDstZone() throws Exception {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz");
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz", Locale.US);
         Calendar calendar = new GregorianCalendar(AUSTRALIA_LORD_HOWE);
         calendar.setTime(format.parse("2011-06-21T20:00 Lord Howe Daylight Time")); // 9:00 GMT+11
         assertEquals(19, calendar.get(Calendar.HOUR_OF_DAY)); // 9:00 GMT+10:30
@@ -207,7 +208,7 @@
     }
 
     public void testNonDstZoneWithDstTimestampForNonHourDstZone() throws Exception {
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz");
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm zzzz", Locale.US);
         Calendar calendar = new GregorianCalendar(AUSTRALIA_LORD_HOWE);
         calendar.setTime(format.parse("2010-12-21T19:30 Lord Howe Standard Time")); //9:00 GMT+10:30
         assertEquals(20, calendar.get(Calendar.HOUR_OF_DAY)); // 9:00 GMT+11:00
@@ -227,4 +228,23 @@
         new SimpleDateFormat("z", Locale.FRANCE).parse("UTC");
         new SimpleDateFormat("z", Locale.US).parse("UTC");
     }
+
+    // http://code.google.com/p/android/issues/detail?id=36689
+    public void testParseArabic() throws Exception {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", new Locale("ar", "EG"));
+        sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
+
+        // Can we parse an ASCII-formatted date in an Arabic locale?
+        Date d = sdf.parse("2012-08-29 10:02:45");
+        assertEquals(1346259765000L, d.getTime());
+
+        // Can we format a date correctly in an Arabic locale?
+        String formatted = sdf.format(d);
+        assertEquals("٢٠١٢-٠٨-٢٩ ١٠:٠٢:٤٥", formatted);
+
+        // Can we parse the Arabic-formatted date in an Arabic locale, and get the same date
+        // we started with?
+        Date d2 = sdf.parse(formatted);
+        assertEquals(d, d2);
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/OldAndroidLocaleTest.java b/luni/src/test/java/libcore/java/util/OldAndroidLocaleTest.java
index 547b70a..8fbe5ff 100644
--- a/luni/src/test/java/libcore/java/util/OldAndroidLocaleTest.java
+++ b/luni/src/test/java/libcore/java/util/OldAndroidLocaleTest.java
@@ -31,7 +31,6 @@
  * resource bundles.
  */
 public class OldAndroidLocaleTest extends TestCase {
-
     // Test basic Locale infrastructure.
     public void testLocale() throws Exception {
         Locale locale = new Locale("en");
@@ -47,49 +46,6 @@
         assertEquals("en_US_POSIX", locale.toString());
     }
 
-    /*
-     * Tests some must-have locales. TODO: Add back "de". See discussion
-     * immediately below this method.
-     */
-    public void testResourceBundles() throws Exception {
-        Locale eng = new Locale("en", "US");
-        DateFormatSymbols engSymbols = new DateFormatSymbols(eng);
-
-        //Locale deu = new Locale("de", "DE");
-        //DateFormatSymbols deuSymbols = new DateFormatSymbols(deu);
-
-        TimeZone berlin = TimeZone.getTimeZone("Europe/Berlin");
-
-        assertEquals("January", engSymbols.getMonths()[0]);
-        //assertEquals("Januar", deuSymbols.getMonths()[0]);
-
-        assertEquals("Sunday", engSymbols.getWeekdays()[Calendar.SUNDAY]);
-        //assertEquals("Sonntag", deuSymbols.getWeekdays()[Calendar.SUNDAY]);
-
-        assertEquals("Central European Time",
-                berlin.getDisplayName(false, TimeZone.LONG, eng));
-        assertEquals("Central European Summer Time",
-                berlin.getDisplayName(true, TimeZone.LONG, eng));
-
-        //assertEquals("Mitteleurop\u00E4ische Zeit",
-        //        berlin.getDisplayName(false, TimeZone.LONG, deu));
-        //assertEquals("Mitteleurop\u00E4ische Sommerzeit",
-        //        berlin.getDisplayName(true, TimeZone.LONG, deu));
-
-        assertTrue(engSymbols.getZoneStrings().length > 100);
-    }
-
-    /*
-     * Disabled version of the above test. The version above omits
-     * checks for stuff in the "de" locale, because we stripped that
-     * out as part of the flash reduction effort (so that we could
-     * still ship on Dream). We expect to have a baseline target that
-     * includes a large enough system partition to include "de"
-     * immediately after the last official release for Dream (whenever
-     * that may be).
-     *
-    // Test some must-have locales.
-    @LargeTest
     public void testResourceBundles() throws Exception {
         Locale eng = new Locale("en", "US");
         DateFormatSymbols engSymbols = new DateFormatSymbols(eng);
@@ -117,7 +73,6 @@
 
         assertTrue(engSymbols.getZoneStrings().length > 100);
     }
-    */
 
     // This one makes sure we have all necessary locales installed.
     // Suppress this flaky test for now.
diff --git a/luni/src/test/java/libcore/java/util/OldScannerTest.java b/luni/src/test/java/libcore/java/util/OldScannerTest.java
index b51cfbc..9bac1f4 100644
--- a/luni/src/test/java/libcore/java/util/OldScannerTest.java
+++ b/luni/src/test/java/libcore/java/util/OldScannerTest.java
@@ -28,7 +28,6 @@
 import java.util.regex.MatchResult;
 import java.util.regex.Pattern;
 import junit.framework.TestCase;
-import tests.support.Support_PortManager;
 
 public final class OldScannerTest extends TestCase {
 
@@ -492,15 +491,12 @@
         assertEquals(102400, matchResult.end());
     }
 
-    public void test_Constructor_LReadableByteChannel()
-            throws IOException {
-        InetSocketAddress localAddr = new InetSocketAddress("127.0.0.1",
-                Support_PortManager.getNextPort());
+    public void test_Constructor_LReadableByteChannel() throws IOException {
         ServerSocketChannel ssc = ServerSocketChannel.open();
-        ssc.socket().bind(localAddr);
+        ssc.socket().bind(null);
 
         SocketChannel sc = SocketChannel.open();
-        sc.connect(localAddr);
+        sc.connect(ssc.socket().getLocalSocketAddress());
         sc.configureBlocking(false);
         assertFalse(sc.isBlocking());
 
diff --git a/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java b/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
index 240403e..4ed89de 100644
--- a/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
@@ -83,6 +83,7 @@
     }
 
     public void test_getDisplayName() {
+        Locale.setDefault(Locale.US);
         TimeZone tz = TimeZone.getTimeZone("GMT-6");
         assertEquals("GMT-06:00", tz.getDisplayName());
         tz = TimeZone.getTimeZone("America/Los_Angeles");
@@ -99,6 +100,7 @@
     }
 
     public void test_getDisplayNameZI() {
+        Locale.setDefault(Locale.US);
         TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
         assertEquals("PST",                   tz.getDisplayName(false, 0));
         assertEquals("Pacific Daylight Time", tz.getDisplayName(true, 1));
@@ -150,15 +152,4 @@
         tz.setID("New ID for GMT-6");
         assertEquals("New ID for GMT-6", tz.getID());
     }
-
-    Locale loc = null;
-
-    protected void setUp() {
-        loc = Locale.getDefault();
-        Locale.setDefault(Locale.US);
-    }
-
-    protected void tearDown() {
-        Locale.setDefault(loc);
-    }
 }
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index d94b017..6e8b8d8 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -17,12 +17,14 @@
 package libcore.java.util;
 
 import java.text.SimpleDateFormat;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
-import java.util.TimeZone;
 import java.util.SimpleTimeZone;
+import java.util.TimeZone;
+import junit.framework.TestCase;
 
-public class TimeZoneTest extends junit.framework.TestCase {
+public class TimeZoneTest extends TestCase {
     // http://code.google.com/p/android/issues/detail?id=877
     public void test_useDaylightTime_Taiwan() {
         TimeZone asiaTaipei = TimeZone.getTimeZone("Asia/Taipei");
@@ -144,8 +146,8 @@
 
     // http://code.google.com/p/android/issues/detail?id=11918
     public void testHasSameRules() throws Exception {
-        TimeZone denver = TimeZone.getTimeZone ("America/Denver") ;
-        TimeZone phoenix = TimeZone.getTimeZone ("America/Phoenix") ;
+        TimeZone denver = TimeZone.getTimeZone("America/Denver");
+        TimeZone phoenix = TimeZone.getTimeZone("America/Phoenix");
         assertFalse(denver.hasSameRules(phoenix));
     }
 
@@ -157,4 +159,56 @@
         } catch (NullPointerException expected) {
         }
     }
+
+    // http://b.corp.google.com/issue?id=6556561
+    public void testCustomZoneIds() throws Exception {
+        // These are all okay (and equivalent).
+        assertEquals("GMT+05:00", TimeZone.getTimeZone("GMT+05:00").getID());
+        assertEquals("GMT+05:00", TimeZone.getTimeZone("GMT+5:00").getID());
+        assertEquals("GMT+05:00", TimeZone.getTimeZone("GMT+0500").getID());
+        assertEquals("GMT+05:00", TimeZone.getTimeZone("GMT+500").getID());
+        assertEquals("GMT+05:00", TimeZone.getTimeZone("GMT+5").getID());
+        // These aren't.
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+5.5").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+5:5").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+5:0").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+5:005").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+5:000").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+005:00").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+05:99").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+28:00").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+05:00.00").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+05:00:00").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+5:").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+junk").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+5junk").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+5:junk").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("GMT+5:00junk").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("junkGMT+5:00").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("junk").getID());
+        assertEquals("GMT", TimeZone.getTimeZone("gmt+5:00").getID());
+    }
+
+    public void test_getDSTSavings() throws Exception {
+      assertEquals(0, TimeZone.getTimeZone("UTC").getDSTSavings());
+      assertEquals(3600000, TimeZone.getTimeZone("America/Los_Angeles").getDSTSavings());
+      assertEquals(1800000, TimeZone.getTimeZone("Australia/Lord_Howe").getDSTSavings());
+    }
+
+    public void testSimpleTimeZoneDoesNotCallOverrideableMethodsFromConstructor() {
+        new SimpleTimeZone(0, "X", Calendar.MARCH, 1, 1, 1, Calendar.SEPTEMBER, 1, 1, 1) {
+            @Override public void setStartRule(int m, int d, int dow, int time) {
+                fail();
+            }
+            @Override public void setStartRule(int m, int d, int dow, int time, boolean after) {
+                fail();
+            }
+            @Override public void setEndRule(int m, int d, int dow, int time) {
+                fail();
+            }
+            @Override public void setEndRule(int m, int d, int dow, int time, boolean after) {
+                fail();
+            }
+        };
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java b/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java
index 450b8d9..07d99e9 100644
--- a/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java
+++ b/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java
@@ -247,19 +247,36 @@
             }
         }
 
-        // Starting index out of region
+        String string3 = "Brave new world";
         Pattern pat3 = Pattern.compile("new");
-        Matcher mat3 = pat3.matcher("Brave new world");
+        Matcher mat3 = pat3.matcher(string3);
 
-        assertTrue(mat3.find(-1));
+        // find(int) throws for out of range indexes.
+        try {
+            mat3.find(-1);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        assertFalse(mat3.find(string3.length()));
+        try {
+            mat3.find(string3.length() + 1);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+        }
+
         assertTrue(mat3.find(6));
         assertFalse(mat3.find(7));
 
         mat3.region(7, 10);
+        assertFalse(mat3.find()); // No "new" in the region.
 
-        assertFalse(mat3.find(3));
-        assertFalse(mat3.find(6));
-        assertFalse(mat3.find(7));
+        assertTrue(mat3.find(3)); // find(int) ignores the region.
+        assertTrue(mat3.find(6)); // find(int) ignores the region.
+        assertFalse(mat3.find(7)); // No "new" >= 7.
+
+        mat3.region(1, 4);
+        assertFalse(mat3.find()); // No "new" in the region.
+        assertTrue(mat3.find(5)); // find(int) ignores the region.
     }
 
     public void testSEOLsymbols() {
@@ -579,4 +596,14 @@
         assertTrue(pattern.matcher("14pt").matches());
     }
 
+    public void testUnicodeCharacterClasses() throws Exception {
+        // http://code.google.com/p/android/issues/detail?id=21176
+        // We use the Unicode TR-18 definitions: http://www.unicode.org/reports/tr18/#Compatibility_Properties
+        assertTrue("\u0666".matches("\\d")); // ARABIC-INDIC DIGIT SIX
+        assertFalse("\u0666".matches("\\D")); // ARABIC-INDIC DIGIT SIX
+        assertTrue("\u1680".matches("\\s")); // OGHAM SPACE MARK
+        assertFalse("\u1680".matches("\\S")); // OGHAM SPACE MARK
+        assertTrue("\u00ea".matches("\\w")); // LATIN SMALL LETTER E WITH CIRCUMFLEX
+        assertFalse("\u00ea".matches("\\W")); // LATIN SMALL LETTER E WITH CIRCUMFLEX
+    }
 }
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index 7919b35..d31825a 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -17,14 +17,489 @@
 package libcore.javax.crypto;
 
 import com.android.org.bouncycastle.asn1.x509.KeyUsage;
+import java.math.BigInteger;
 import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.Provider.Service;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
 import java.security.cert.Certificate;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.IllegalBlockSizeException;
 import junit.framework.TestCase;
 import libcore.java.security.TestKeyStore;
 
 public final class CipherTest extends TestCase {
 
+    private static boolean isUnsupported(String algorithm) {
+        if (algorithm.equals("PBEWITHMD5ANDRC2")) {
+            return true;
+        }
+        if (algorithm.equals("PBEWITHSHA1ANDRC2")) {
+            return true;
+        }
+        if (algorithm.equals("PBEWITHSHAAND40BITRC2-CBC")) {
+            return true;
+        }
+        if (algorithm.equals("PBEWITHSHAAND128BITRC2-CBC")) {
+            return true;
+        }
+        if (algorithm.equals("PBEWITHSHAANDTWOFISH-CBC")) {
+            return true;
+        }
+        return false;
+    }
+
+    private synchronized static int getEncryptMode(String algorithm) throws Exception {
+        if (isWrap(algorithm)) {
+            return Cipher.WRAP_MODE;
+        }
+        return Cipher.ENCRYPT_MODE;
+    }
+
+    private synchronized static int getDecryptMode(String algorithm) throws Exception {
+        if (isWrap(algorithm)) {
+            return Cipher.UNWRAP_MODE;
+        }
+        return Cipher.DECRYPT_MODE;
+    }
+
+    private static String getBaseAlgoritm(String algorithm) {
+        if (algorithm.equals("AESWRAP")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHMD5AND128BITAES-CBC-OPENSSL")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHMD5AND192BITAES-CBC-OPENSSL")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHMD5AND256BITAES-CBC-OPENSSL")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHSHA256AND128BITAES-CBC-BC")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHSHA256AND192BITAES-CBC-BC")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHSHA256AND256BITAES-CBC-BC")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHSHAAND128BITAES-CBC-BC")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHSHAAND192BITAES-CBC-BC")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHSHAAND256BITAES-CBC-BC")) {
+            return "AES";
+        }
+        if (algorithm.equals("PBEWITHMD5ANDDES")) {
+            return "DES";
+        }
+        if (algorithm.equals("PBEWITHSHA1ANDDES")) {
+            return "DES";
+        }
+        if (algorithm.equals("DESEDEWRAP")) {
+            return "DESede";
+        }
+        if (algorithm.equals("PBEWITHSHAAND2-KEYTRIPLEDES-CBC")) {
+            return "DESede";
+        }
+        if (algorithm.equals("PBEWITHSHAAND3-KEYTRIPLEDES-CBC")) {
+            return "DESede";
+        }
+        if (algorithm.equals("RSA/ECB/NoPadding")) {
+            return "RSA";
+        }
+        if (algorithm.equals("RSA/ECB/PKCS1Padding")) {
+            return "RSA";
+        }
+        if (algorithm.equals("PBEWITHSHAAND40BITRC4")) {
+            return "ARC4";
+        }
+        if (algorithm.equals("PBEWITHSHAAND128BITRC4")) {
+            return "ARC4";
+        }
+        return algorithm;
+    }
+
+    private static boolean isAsymmetric(String algorithm) {
+        return getBaseAlgoritm(algorithm).equals("RSA");
+    }
+
+    private static boolean isWrap(String algorithm) {
+        return algorithm.endsWith("WRAP");
+    }
+
+    private static Map<String, Key> ENCRYPT_KEYS = new HashMap<String, Key>();
+    private synchronized static Key getEncryptKey(String algorithm) throws Exception {
+        Key key = ENCRYPT_KEYS.get(algorithm);
+        if (key != null) {
+            return key;
+        }
+        algorithm = getBaseAlgoritm(algorithm);
+        if (algorithm.equals("RSA")) {
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                                                              RSA_2048_privateExponent);
+            key = kf.generatePrivate(keySpec);
+        } else {
+            KeyGenerator kg = KeyGenerator.getInstance(algorithm);
+            key = kg.generateKey();
+        }
+        ENCRYPT_KEYS.put(algorithm, key);
+        return key;
+    }
+
+    private static Map<String, Key> DECRYPT_KEYS = new HashMap<String, Key>();
+    private synchronized static Key getDecryptKey(String algorithm) throws Exception {
+        Key key = DECRYPT_KEYS.get(algorithm);
+        if (key != null) {
+            return key;
+        }
+        algorithm = getBaseAlgoritm(algorithm);
+        if (algorithm.equals("RSA")) {
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                                                            RSA_2048_publicExponent);
+            key = kf.generatePublic(keySpec);
+        } else {
+            assertFalse(algorithm, isAsymmetric(algorithm));
+            key = getEncryptKey(algorithm);
+        }
+        DECRYPT_KEYS.put(algorithm, key);
+        return key;
+    }
+
+    private static Map<String, Integer> EXPECTED_BLOCK_SIZE = new HashMap<String, Integer>();
+    static {
+        EXPECTED_BLOCK_SIZE.put("AES", 16);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHA256AND128BITAES-CBC-BC", 16);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHA256AND192BITAES-CBC-BC", 16);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHA256AND256BITAES-CBC-BC", 16);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND128BITAES-CBC-BC", 16);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND192BITAES-CBC-BC", 16);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND256BITAES-CBC-BC", 16);
+
+        EXPECTED_BLOCK_SIZE.put("AESWRAP", 0);
+
+        EXPECTED_BLOCK_SIZE.put("ARC4", 0);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND40BITRC4", 0);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND128BITRC4", 0);
+
+        EXPECTED_BLOCK_SIZE.put("BLOWFISH", 8);
+
+        EXPECTED_BLOCK_SIZE.put("DES", 8);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHMD5ANDDES", 8);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHA1ANDDES", 8);
+
+        EXPECTED_BLOCK_SIZE.put("DESEDE", 8);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8);
+        EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8);
+
+        EXPECTED_BLOCK_SIZE.put("DESEDEWRAP", 0);
+
+        EXPECTED_BLOCK_SIZE.put("RSA", 255);
+        EXPECTED_BLOCK_SIZE.put("RSA/ECB/NoPadding", 0);
+        EXPECTED_BLOCK_SIZE.put("RSA/ECB/PKCS1Padding", 0);
+    }
+    private static int getExpectedBlockSize(String algorithm) {
+        Integer expected = EXPECTED_BLOCK_SIZE.get(algorithm);
+        assertNotNull(algorithm, expected);
+        return expected;
+    }
+
+    private static Map<String, Integer> EXPECTED_OUTPUT_SIZE = new HashMap<String, Integer>();
+    static {
+        EXPECTED_OUTPUT_SIZE.put("AES", 16);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA256AND128BITAES-CBC-BC", 16);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA256AND192BITAES-CBC-BC", 16);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA256AND256BITAES-CBC-BC", 16);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND128BITAES-CBC-BC", 16);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND192BITAES-CBC-BC", 16);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND256BITAES-CBC-BC", 16);
+
+        EXPECTED_OUTPUT_SIZE.put("AESWRAP", -1);
+
+        EXPECTED_OUTPUT_SIZE.put("ARC4", 0);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND40BITRC4", 0);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND128BITRC4", 0);
+
+        EXPECTED_OUTPUT_SIZE.put("BLOWFISH", 8);
+
+        EXPECTED_OUTPUT_SIZE.put("DES", 8);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5ANDDES", 8);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA1ANDDES", 8);
+
+        EXPECTED_OUTPUT_SIZE.put("DESEDE", 8);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8);
+        EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8);
+
+        EXPECTED_OUTPUT_SIZE.put("DESEDEWRAP", -1);
+
+        EXPECTED_OUTPUT_SIZE.put("RSA", 256);
+        EXPECTED_OUTPUT_SIZE.put("RSA/ECB/NoPadding", 256);
+        EXPECTED_OUTPUT_SIZE.put("RSA/ECB/PKCS1Padding", 256);
+    }
+    private static int getExpectedOutputSize(String algorithm) {
+        Integer expected = EXPECTED_OUTPUT_SIZE.get(algorithm);
+        assertNotNull(algorithm, expected);
+        return expected;
+    }
+
+    private static byte[] ORIGINAL_PLAIN_TEXT = new byte[] { 0x0a, 0x0b, 0x0c };
+    private static byte[] PKCS1_BLOCK_TYPE_00_PADDED_PLAIN_TEXT = new byte[] {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0x0b, 0x0c
+    };
+    private static byte[] PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT = new byte[] {
+        (byte) 0x00, (byte) 0x01, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c
+    };
+    private static byte[] PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT = new byte[] {
+        (byte) 0x00, (byte) 0x02, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c
+    };
+
+    private static byte[] getExpectedPlainText(String algorithm) {
+        if (algorithm.equals("RSA/ECB/NoPadding")) {
+            return PKCS1_BLOCK_TYPE_00_PADDED_PLAIN_TEXT;
+        }
+        return ORIGINAL_PLAIN_TEXT;
+    }
+
+    public void test_getInstance() throws Exception {
+        Provider[] providers = Security.getProviders();
+        for (Provider provider : providers) {
+            Set<Provider.Service> services = provider.getServices();
+            for (Provider.Service service : services) {
+                String type = service.getType();
+                if (!type.equals("Cipher")) {
+                    continue;
+                }
+                String algorithm = service.getAlgorithm();
+                try {
+                    // Cipher.getInstance(String)
+                    Cipher c1 = Cipher.getInstance(algorithm);
+                    assertEquals(algorithm, c1.getAlgorithm());
+                    test_Cipher(c1);
+
+                    // Cipher.getInstance(String, Provider)
+                    Cipher c2 = Cipher.getInstance(algorithm, provider);
+                    assertEquals(algorithm, c2.getAlgorithm());
+                    assertEquals(provider, c2.getProvider());
+                    test_Cipher(c2);
+
+                    // KeyGenerator.getInstance(String, String)
+                    Cipher c3 = Cipher.getInstance(algorithm, provider.getName());
+                    assertEquals(algorithm, c3.getAlgorithm());
+                    assertEquals(provider, c3.getProvider());
+                    test_Cipher(c3);
+                } catch (Throwable e) {
+                    throw new Exception("Problem testing Cipher." + algorithm, e);
+                }
+            }
+        }
+    }
+
+    private void test_Cipher(Cipher c) throws Exception {
+        // TODO: test all supported modes and padding for a given algorithm
+        String algorithm = c.getAlgorithm();
+        if (isUnsupported(algorithm)) {
+            return;
+        }
+
+        try {
+            c.getOutputSize(0);
+        } catch (IllegalStateException expected) {
+        }
+
+        // TODO: test keys from different factories (e.g. OpenSSLRSAPrivateKey vs JCERSAPrivateKey)
+        Key encryptKey = getEncryptKey(algorithm);
+        c.init(getEncryptMode(algorithm), encryptKey);
+
+        assertEquals(getExpectedBlockSize(algorithm), c.getBlockSize());
+
+        assertEquals(getExpectedOutputSize(algorithm), c.getOutputSize(0));
+
+        // TODO: test Cipher.getIV()
+
+        // TODO: test Cipher.getParameters()
+
+        assertNull(c.getExemptionMechanism());
+
+        if (isWrap(algorithm)) {
+            byte[] cipherText = c.wrap(encryptKey);
+            c.init(getDecryptMode(algorithm), getDecryptKey(algorithm));
+            int keyType = (isAsymmetric(algorithm)) ? Cipher.PRIVATE_KEY : Cipher.SECRET_KEY;
+            Key decryptedKey = c.unwrap(cipherText, encryptKey.getAlgorithm(), keyType);
+            assertEquals("encryptKey.getAlgorithm()=" + encryptKey.getAlgorithm()
+                         + " decryptedKey.getAlgorithm()=" + decryptedKey.getAlgorithm()
+                         + " encryptKey.getEncoded()=" + Arrays.toString(encryptKey.getEncoded())
+                         + " decryptedKey.getEncoded()=" + Arrays.toString(decryptedKey.getEncoded()),
+                         encryptKey, decryptedKey);
+        } else {
+            byte[] cipherText = c.doFinal(ORIGINAL_PLAIN_TEXT);
+            c.init(getDecryptMode(algorithm), getDecryptKey(algorithm));
+            byte[] decryptedPlainText = c.doFinal(cipherText);
+            assertEquals(Arrays.toString(getExpectedPlainText(algorithm)),
+                         Arrays.toString(decryptedPlainText));
+        }
+    }
+
+    public void testInputPKCS1Padding() throws Exception {
+        testInputPKCS1Padding(PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
+        try {
+            testInputPKCS1Padding(PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
+            fail();
+        } catch (BadPaddingException expected) {
+        }
+        try {
+            testInputPKCS1Padding(PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
+            fail();
+        } catch (BadPaddingException expected) {
+        }
+        testInputPKCS1Padding(PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
+    }
+
+    private void testInputPKCS1Padding(byte[] prePaddedPlainText, Key encryptKey, Key decryptKey) throws Exception {
+        Cipher encryptCipher = Cipher.getInstance("RSA/ECB/NoPadding");
+        encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey);
+        byte[] cipherText = encryptCipher.doFinal(prePaddedPlainText);
+        Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+        decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey);
+        byte[] plainText = decryptCipher.doFinal(cipherText);
+        assertEquals(Arrays.toString(ORIGINAL_PLAIN_TEXT),
+                     Arrays.toString(plainText));
+    }
+
+    public void testOutputPKCS1Padding() throws Exception {
+       testOutputPKCS1Padding((byte) 1, getEncryptKey("RSA"), getDecryptKey("RSA"));
+       testOutputPKCS1Padding((byte) 2, getDecryptKey("RSA"), getEncryptKey("RSA"));
+    }
+
+    private void testOutputPKCS1Padding(byte expectedBlockType, Key encryptKey, Key decryptKey) throws Exception {
+        Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+        encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey);
+        byte[] cipherText = encryptCipher.doFinal(ORIGINAL_PLAIN_TEXT);
+        Cipher decryptCipher = Cipher.getInstance("RSA/ECB/NoPadding");
+        decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey);
+        byte[] plainText = decryptCipher.doFinal(cipherText);
+        assertPadding(expectedBlockType, ORIGINAL_PLAIN_TEXT, plainText);
+    }
+
+    private void assertPadding(byte expectedBlockType, byte[] expectedData, byte[] actualDataWithPadding) {
+        assertNotNull(actualDataWithPadding);
+        assertEquals(getExpectedOutputSize("RSA"), actualDataWithPadding.length);
+        assertEquals(0, actualDataWithPadding[0]);
+        byte actualBlockType = actualDataWithPadding[1];
+        assertEquals(expectedBlockType, actualBlockType);
+        int actualDataOffset = actualDataWithPadding.length - expectedData.length;
+        if (actualBlockType == 1) {
+            for (int i = 2; i < actualDataOffset - 1; i++) {
+                assertEquals((byte) 0xFF, actualDataWithPadding[i]);
+            }
+        }
+        assertEquals(0x00, actualDataWithPadding[actualDataOffset-1]);
+        byte[] actualData = new byte[expectedData.length];
+        System.arraycopy(actualDataWithPadding, actualDataOffset, actualData, 0, actualData.length);
+        assertEquals(Arrays.toString(expectedData), Arrays.toString(actualData));
+    }
+
     public void testCipherInitWithCertificate () throws Exception {
         // no key usage specified, everything is fine
         assertCipherInitWithKeyUsage(0,                         true,  true, true,  true);
@@ -108,4 +583,774 @@
                 .build()
                 .getPrivateKey("RSA", "RSA").getCertificate();
     }
+
+    /*
+     * Test vectors generated with this private key:
+     *
+     * -----BEGIN RSA PRIVATE KEY-----
+     * MIIEpAIBAAKCAQEA4Ec+irjyKE/rnnQv+XSPoRjtmGM8kvUq63ouvg075gMpvnZq
+     * 0Q62pRXQ0s/ZvqeTDwwwZTeJn3lYzT6FsB+IGFJNMSWEqUslHjYltUFB7b/uGYgI
+     * 4buX/Hy0m56qr2jpyY19DtxTu8D6ADQ1bWMF+7zDxwAUBThqu8hzyw8+90JfPTPf
+     * ezFa4DbSoLZq/UdQOxab8247UWJRW3Ff2oPeryxYrrmr+zCXw8yd2dvl7ylsF2E5
+     * Ao6KZx5jBW1F9AGI0sQTNJCEXeUsJTTpxrJHjAe9rpKII7YtBmx3cPn2Pz26JH9T
+     * CER0e+eqqF2FO4vSRKzsPePImrRkU6tNJMOsaQIDAQABAoIBADd4R3al8XaY9ayW
+     * DfuDobZ1ZOZIvQWXz4q4CHGG8macJ6nsvdSA8Bl6gNBzCebGqW+SUzHlf4tKxvTU
+     * XtpFojJpwJ/EKMB6Tm7fc4oV3sl/q9Lyu0ehTyDqcvz+TDbgGtp3vRN82NTaELsW
+     * LpSkZilx8XX5hfoYjwVsuX7igW9Dq503R2Ekhs2owWGWwwgYqZXshdOEZ3kSZ7O/
+     * IfJzcQppJYYldoQcW2cSwS1L0govMpmtt8E12l6VFavadufK8qO+gFUdBzt4vxFi
+     * xIrSt/R0OgI47k0lL31efmUzzK5kzLOTYAdaL9HgNOw65c6cQIzL8OJeQRQCFoez
+     * 3UdUroECgYEA9UGIS8Nzeyki1BGe9F4t7izUy7dfRVBaFXqlAJ+Zxzot8HJKxGAk
+     * MGMy6omBd2NFRl3G3x4KbxQK/ztzluaomUrF2qloc0cv43dJ0U6z4HXmKdvrNYMz
+     * im82SdCiZUp6Qv2atr+krE1IHTkLsimwZL3DEcwb4bYxidp8QM3s8rECgYEA6hp0
+     * LduIHO23KIyH442GjdekCdFaQ/RF1Td6C1cx3b/KLa8oqOE81cCvzsM0fXSjniNa
+     * PNljPydN4rlPkt9DgzkR2enxz1jyfeLgj/RZZMcg0+whOdx8r8kSlTzeyy81Wi4s
+     * NaUPrXVMs7IxZkJLo7bjESoriYw4xcFe2yOGkzkCgYBRgo8exv2ZYCmQG68dfjN7
+     * pfCvJ+mE6tiVrOYr199O5FoiQInyzBUa880XP84EdLywTzhqLNzA4ANrokGfVFeS
+     * YtRxAL6TGYSj76Bb7PFBV03AebOpXEqD5sQ/MhTW3zLVEt4ZgIXlMeYWuD/X3Z0f
+     * TiYHwzM9B8VdEH0dOJNYcQKBgQDbT7UPUN6O21P/NMgJMYigUShn2izKBIl3WeWH
+     * wkQBDa+GZNWegIPRbBZHiTAfZ6nweAYNg0oq29NnV1toqKhCwrAqibPzH8zsiiL+
+     * OVeVxcbHQitOXXSh6ajzDndZufwtY5wfFWc+hOk6XvFQb0MVODw41Fy9GxQEj0ch
+     * 3IIyYQKBgQDYEUWTr0FfthLb8ZI3ENVNB0hiBadqO0MZSWjA3/HxHvD2GkozfV/T
+     * dBu8lkDkR7i2tsR8OsEgQ1fTsMVbqShr2nP2KSlvX6kUbYl2NX08dR51FIaWpAt0
+     * aFyCzjCQLWOdck/yTV4ulAfuNO3tLjtN9lqpvP623yjQe6aQPxZXaA==
+     * -----END RSA PRIVATE KEY-----
+     *
+     */
+
+    private static final BigInteger RSA_2048_modulus = new BigInteger(new byte[] {
+        (byte) 0x00, (byte) 0xe0, (byte) 0x47, (byte) 0x3e, (byte) 0x8a, (byte) 0xb8, (byte) 0xf2, (byte) 0x28,
+        (byte) 0x4f, (byte) 0xeb, (byte) 0x9e, (byte) 0x74, (byte) 0x2f, (byte) 0xf9, (byte) 0x74, (byte) 0x8f,
+        (byte) 0xa1, (byte) 0x18, (byte) 0xed, (byte) 0x98, (byte) 0x63, (byte) 0x3c, (byte) 0x92, (byte) 0xf5,
+        (byte) 0x2a, (byte) 0xeb, (byte) 0x7a, (byte) 0x2e, (byte) 0xbe, (byte) 0x0d, (byte) 0x3b, (byte) 0xe6,
+        (byte) 0x03, (byte) 0x29, (byte) 0xbe, (byte) 0x76, (byte) 0x6a, (byte) 0xd1, (byte) 0x0e, (byte) 0xb6,
+        (byte) 0xa5, (byte) 0x15, (byte) 0xd0, (byte) 0xd2, (byte) 0xcf, (byte) 0xd9, (byte) 0xbe, (byte) 0xa7,
+        (byte) 0x93, (byte) 0x0f, (byte) 0x0c, (byte) 0x30, (byte) 0x65, (byte) 0x37, (byte) 0x89, (byte) 0x9f,
+        (byte) 0x79, (byte) 0x58, (byte) 0xcd, (byte) 0x3e, (byte) 0x85, (byte) 0xb0, (byte) 0x1f, (byte) 0x88,
+        (byte) 0x18, (byte) 0x52, (byte) 0x4d, (byte) 0x31, (byte) 0x25, (byte) 0x84, (byte) 0xa9, (byte) 0x4b,
+        (byte) 0x25, (byte) 0x1e, (byte) 0x36, (byte) 0x25, (byte) 0xb5, (byte) 0x41, (byte) 0x41, (byte) 0xed,
+        (byte) 0xbf, (byte) 0xee, (byte) 0x19, (byte) 0x88, (byte) 0x08, (byte) 0xe1, (byte) 0xbb, (byte) 0x97,
+        (byte) 0xfc, (byte) 0x7c, (byte) 0xb4, (byte) 0x9b, (byte) 0x9e, (byte) 0xaa, (byte) 0xaf, (byte) 0x68,
+        (byte) 0xe9, (byte) 0xc9, (byte) 0x8d, (byte) 0x7d, (byte) 0x0e, (byte) 0xdc, (byte) 0x53, (byte) 0xbb,
+        (byte) 0xc0, (byte) 0xfa, (byte) 0x00, (byte) 0x34, (byte) 0x35, (byte) 0x6d, (byte) 0x63, (byte) 0x05,
+        (byte) 0xfb, (byte) 0xbc, (byte) 0xc3, (byte) 0xc7, (byte) 0x00, (byte) 0x14, (byte) 0x05, (byte) 0x38,
+        (byte) 0x6a, (byte) 0xbb, (byte) 0xc8, (byte) 0x73, (byte) 0xcb, (byte) 0x0f, (byte) 0x3e, (byte) 0xf7,
+        (byte) 0x42, (byte) 0x5f, (byte) 0x3d, (byte) 0x33, (byte) 0xdf, (byte) 0x7b, (byte) 0x31, (byte) 0x5a,
+        (byte) 0xe0, (byte) 0x36, (byte) 0xd2, (byte) 0xa0, (byte) 0xb6, (byte) 0x6a, (byte) 0xfd, (byte) 0x47,
+        (byte) 0x50, (byte) 0x3b, (byte) 0x16, (byte) 0x9b, (byte) 0xf3, (byte) 0x6e, (byte) 0x3b, (byte) 0x51,
+        (byte) 0x62, (byte) 0x51, (byte) 0x5b, (byte) 0x71, (byte) 0x5f, (byte) 0xda, (byte) 0x83, (byte) 0xde,
+        (byte) 0xaf, (byte) 0x2c, (byte) 0x58, (byte) 0xae, (byte) 0xb9, (byte) 0xab, (byte) 0xfb, (byte) 0x30,
+        (byte) 0x97, (byte) 0xc3, (byte) 0xcc, (byte) 0x9d, (byte) 0xd9, (byte) 0xdb, (byte) 0xe5, (byte) 0xef,
+        (byte) 0x29, (byte) 0x6c, (byte) 0x17, (byte) 0x61, (byte) 0x39, (byte) 0x02, (byte) 0x8e, (byte) 0x8a,
+        (byte) 0x67, (byte) 0x1e, (byte) 0x63, (byte) 0x05, (byte) 0x6d, (byte) 0x45, (byte) 0xf4, (byte) 0x01,
+        (byte) 0x88, (byte) 0xd2, (byte) 0xc4, (byte) 0x13, (byte) 0x34, (byte) 0x90, (byte) 0x84, (byte) 0x5d,
+        (byte) 0xe5, (byte) 0x2c, (byte) 0x25, (byte) 0x34, (byte) 0xe9, (byte) 0xc6, (byte) 0xb2, (byte) 0x47,
+        (byte) 0x8c, (byte) 0x07, (byte) 0xbd, (byte) 0xae, (byte) 0x92, (byte) 0x88, (byte) 0x23, (byte) 0xb6,
+        (byte) 0x2d, (byte) 0x06, (byte) 0x6c, (byte) 0x77, (byte) 0x70, (byte) 0xf9, (byte) 0xf6, (byte) 0x3f,
+        (byte) 0x3d, (byte) 0xba, (byte) 0x24, (byte) 0x7f, (byte) 0x53, (byte) 0x08, (byte) 0x44, (byte) 0x74,
+        (byte) 0x7b, (byte) 0xe7, (byte) 0xaa, (byte) 0xa8, (byte) 0x5d, (byte) 0x85, (byte) 0x3b, (byte) 0x8b,
+        (byte) 0xd2, (byte) 0x44, (byte) 0xac, (byte) 0xec, (byte) 0x3d, (byte) 0xe3, (byte) 0xc8, (byte) 0x9a,
+        (byte) 0xb4, (byte) 0x64, (byte) 0x53, (byte) 0xab, (byte) 0x4d, (byte) 0x24, (byte) 0xc3, (byte) 0xac,
+        (byte) 0x69,
+    });
+
+    private static final BigInteger RSA_2048_privateExponent = new BigInteger(new byte[] {
+        (byte) 0x37, (byte) 0x78, (byte) 0x47, (byte) 0x76, (byte) 0xa5, (byte) 0xf1, (byte) 0x76, (byte) 0x98,
+        (byte) 0xf5, (byte) 0xac, (byte) 0x96, (byte) 0x0d, (byte) 0xfb, (byte) 0x83, (byte) 0xa1, (byte) 0xb6,
+        (byte) 0x75, (byte) 0x64, (byte) 0xe6, (byte) 0x48, (byte) 0xbd, (byte) 0x05, (byte) 0x97, (byte) 0xcf,
+        (byte) 0x8a, (byte) 0xb8, (byte) 0x08, (byte) 0x71, (byte) 0x86, (byte) 0xf2, (byte) 0x66, (byte) 0x9c,
+        (byte) 0x27, (byte) 0xa9, (byte) 0xec, (byte) 0xbd, (byte) 0xd4, (byte) 0x80, (byte) 0xf0, (byte) 0x19,
+        (byte) 0x7a, (byte) 0x80, (byte) 0xd0, (byte) 0x73, (byte) 0x09, (byte) 0xe6, (byte) 0xc6, (byte) 0xa9,
+        (byte) 0x6f, (byte) 0x92, (byte) 0x53, (byte) 0x31, (byte) 0xe5, (byte) 0x7f, (byte) 0x8b, (byte) 0x4a,
+        (byte) 0xc6, (byte) 0xf4, (byte) 0xd4, (byte) 0x5e, (byte) 0xda, (byte) 0x45, (byte) 0xa2, (byte) 0x32,
+        (byte) 0x69, (byte) 0xc0, (byte) 0x9f, (byte) 0xc4, (byte) 0x28, (byte) 0xc0, (byte) 0x7a, (byte) 0x4e,
+        (byte) 0x6e, (byte) 0xdf, (byte) 0x73, (byte) 0x8a, (byte) 0x15, (byte) 0xde, (byte) 0xc9, (byte) 0x7f,
+        (byte) 0xab, (byte) 0xd2, (byte) 0xf2, (byte) 0xbb, (byte) 0x47, (byte) 0xa1, (byte) 0x4f, (byte) 0x20,
+        (byte) 0xea, (byte) 0x72, (byte) 0xfc, (byte) 0xfe, (byte) 0x4c, (byte) 0x36, (byte) 0xe0, (byte) 0x1a,
+        (byte) 0xda, (byte) 0x77, (byte) 0xbd, (byte) 0x13, (byte) 0x7c, (byte) 0xd8, (byte) 0xd4, (byte) 0xda,
+        (byte) 0x10, (byte) 0xbb, (byte) 0x16, (byte) 0x2e, (byte) 0x94, (byte) 0xa4, (byte) 0x66, (byte) 0x29,
+        (byte) 0x71, (byte) 0xf1, (byte) 0x75, (byte) 0xf9, (byte) 0x85, (byte) 0xfa, (byte) 0x18, (byte) 0x8f,
+        (byte) 0x05, (byte) 0x6c, (byte) 0xb9, (byte) 0x7e, (byte) 0xe2, (byte) 0x81, (byte) 0x6f, (byte) 0x43,
+        (byte) 0xab, (byte) 0x9d, (byte) 0x37, (byte) 0x47, (byte) 0x61, (byte) 0x24, (byte) 0x86, (byte) 0xcd,
+        (byte) 0xa8, (byte) 0xc1, (byte) 0x61, (byte) 0x96, (byte) 0xc3, (byte) 0x08, (byte) 0x18, (byte) 0xa9,
+        (byte) 0x95, (byte) 0xec, (byte) 0x85, (byte) 0xd3, (byte) 0x84, (byte) 0x67, (byte) 0x79, (byte) 0x12,
+        (byte) 0x67, (byte) 0xb3, (byte) 0xbf, (byte) 0x21, (byte) 0xf2, (byte) 0x73, (byte) 0x71, (byte) 0x0a,
+        (byte) 0x69, (byte) 0x25, (byte) 0x86, (byte) 0x25, (byte) 0x76, (byte) 0x84, (byte) 0x1c, (byte) 0x5b,
+        (byte) 0x67, (byte) 0x12, (byte) 0xc1, (byte) 0x2d, (byte) 0x4b, (byte) 0xd2, (byte) 0x0a, (byte) 0x2f,
+        (byte) 0x32, (byte) 0x99, (byte) 0xad, (byte) 0xb7, (byte) 0xc1, (byte) 0x35, (byte) 0xda, (byte) 0x5e,
+        (byte) 0x95, (byte) 0x15, (byte) 0xab, (byte) 0xda, (byte) 0x76, (byte) 0xe7, (byte) 0xca, (byte) 0xf2,
+        (byte) 0xa3, (byte) 0xbe, (byte) 0x80, (byte) 0x55, (byte) 0x1d, (byte) 0x07, (byte) 0x3b, (byte) 0x78,
+        (byte) 0xbf, (byte) 0x11, (byte) 0x62, (byte) 0xc4, (byte) 0x8a, (byte) 0xd2, (byte) 0xb7, (byte) 0xf4,
+        (byte) 0x74, (byte) 0x3a, (byte) 0x02, (byte) 0x38, (byte) 0xee, (byte) 0x4d, (byte) 0x25, (byte) 0x2f,
+        (byte) 0x7d, (byte) 0x5e, (byte) 0x7e, (byte) 0x65, (byte) 0x33, (byte) 0xcc, (byte) 0xae, (byte) 0x64,
+        (byte) 0xcc, (byte) 0xb3, (byte) 0x93, (byte) 0x60, (byte) 0x07, (byte) 0x5a, (byte) 0x2f, (byte) 0xd1,
+        (byte) 0xe0, (byte) 0x34, (byte) 0xec, (byte) 0x3a, (byte) 0xe5, (byte) 0xce, (byte) 0x9c, (byte) 0x40,
+        (byte) 0x8c, (byte) 0xcb, (byte) 0xf0, (byte) 0xe2, (byte) 0x5e, (byte) 0x41, (byte) 0x14, (byte) 0x02,
+        (byte) 0x16, (byte) 0x87, (byte) 0xb3, (byte) 0xdd, (byte) 0x47, (byte) 0x54, (byte) 0xae, (byte) 0x81,
+    });
+
+    private static final BigInteger RSA_2048_publicExponent = new BigInteger(new byte[] {
+        (byte) 0x01, (byte) 0x00, (byte) 0x01,
+    });
+
+    private static final BigInteger RSA_2048_primeP = new BigInteger(new byte[] {
+        (byte) 0x00, (byte) 0xf5, (byte) 0x41, (byte) 0x88, (byte) 0x4b, (byte) 0xc3, (byte) 0x73, (byte) 0x7b,
+        (byte) 0x29, (byte) 0x22, (byte) 0xd4, (byte) 0x11, (byte) 0x9e, (byte) 0xf4, (byte) 0x5e, (byte) 0x2d,
+        (byte) 0xee, (byte) 0x2c, (byte) 0xd4, (byte) 0xcb, (byte) 0xb7, (byte) 0x5f, (byte) 0x45, (byte) 0x50,
+        (byte) 0x5a, (byte) 0x15, (byte) 0x7a, (byte) 0xa5, (byte) 0x00, (byte) 0x9f, (byte) 0x99, (byte) 0xc7,
+        (byte) 0x3a, (byte) 0x2d, (byte) 0xf0, (byte) 0x72, (byte) 0x4a, (byte) 0xc4, (byte) 0x60, (byte) 0x24,
+        (byte) 0x30, (byte) 0x63, (byte) 0x32, (byte) 0xea, (byte) 0x89, (byte) 0x81, (byte) 0x77, (byte) 0x63,
+        (byte) 0x45, (byte) 0x46, (byte) 0x5d, (byte) 0xc6, (byte) 0xdf, (byte) 0x1e, (byte) 0x0a, (byte) 0x6f,
+        (byte) 0x14, (byte) 0x0a, (byte) 0xff, (byte) 0x3b, (byte) 0x73, (byte) 0x96, (byte) 0xe6, (byte) 0xa8,
+        (byte) 0x99, (byte) 0x4a, (byte) 0xc5, (byte) 0xda, (byte) 0xa9, (byte) 0x68, (byte) 0x73, (byte) 0x47,
+        (byte) 0x2f, (byte) 0xe3, (byte) 0x77, (byte) 0x49, (byte) 0xd1, (byte) 0x4e, (byte) 0xb3, (byte) 0xe0,
+        (byte) 0x75, (byte) 0xe6, (byte) 0x29, (byte) 0xdb, (byte) 0xeb, (byte) 0x35, (byte) 0x83, (byte) 0x33,
+        (byte) 0x8a, (byte) 0x6f, (byte) 0x36, (byte) 0x49, (byte) 0xd0, (byte) 0xa2, (byte) 0x65, (byte) 0x4a,
+        (byte) 0x7a, (byte) 0x42, (byte) 0xfd, (byte) 0x9a, (byte) 0xb6, (byte) 0xbf, (byte) 0xa4, (byte) 0xac,
+        (byte) 0x4d, (byte) 0x48, (byte) 0x1d, (byte) 0x39, (byte) 0x0b, (byte) 0xb2, (byte) 0x29, (byte) 0xb0,
+        (byte) 0x64, (byte) 0xbd, (byte) 0xc3, (byte) 0x11, (byte) 0xcc, (byte) 0x1b, (byte) 0xe1, (byte) 0xb6,
+        (byte) 0x31, (byte) 0x89, (byte) 0xda, (byte) 0x7c, (byte) 0x40, (byte) 0xcd, (byte) 0xec, (byte) 0xf2,
+        (byte) 0xb1,
+    });
+
+    private static final BigInteger RSA_2048_primeQ = new BigInteger(new byte[] {
+        (byte) 0x00, (byte) 0xea, (byte) 0x1a, (byte) 0x74, (byte) 0x2d, (byte) 0xdb, (byte) 0x88, (byte) 0x1c,
+        (byte) 0xed, (byte) 0xb7, (byte) 0x28, (byte) 0x8c, (byte) 0x87, (byte) 0xe3, (byte) 0x8d, (byte) 0x86,
+        (byte) 0x8d, (byte) 0xd7, (byte) 0xa4, (byte) 0x09, (byte) 0xd1, (byte) 0x5a, (byte) 0x43, (byte) 0xf4,
+        (byte) 0x45, (byte) 0xd5, (byte) 0x37, (byte) 0x7a, (byte) 0x0b, (byte) 0x57, (byte) 0x31, (byte) 0xdd,
+        (byte) 0xbf, (byte) 0xca, (byte) 0x2d, (byte) 0xaf, (byte) 0x28, (byte) 0xa8, (byte) 0xe1, (byte) 0x3c,
+        (byte) 0xd5, (byte) 0xc0, (byte) 0xaf, (byte) 0xce, (byte) 0xc3, (byte) 0x34, (byte) 0x7d, (byte) 0x74,
+        (byte) 0xa3, (byte) 0x9e, (byte) 0x23, (byte) 0x5a, (byte) 0x3c, (byte) 0xd9, (byte) 0x63, (byte) 0x3f,
+        (byte) 0x27, (byte) 0x4d, (byte) 0xe2, (byte) 0xb9, (byte) 0x4f, (byte) 0x92, (byte) 0xdf, (byte) 0x43,
+        (byte) 0x83, (byte) 0x39, (byte) 0x11, (byte) 0xd9, (byte) 0xe9, (byte) 0xf1, (byte) 0xcf, (byte) 0x58,
+        (byte) 0xf2, (byte) 0x7d, (byte) 0xe2, (byte) 0xe0, (byte) 0x8f, (byte) 0xf4, (byte) 0x59, (byte) 0x64,
+        (byte) 0xc7, (byte) 0x20, (byte) 0xd3, (byte) 0xec, (byte) 0x21, (byte) 0x39, (byte) 0xdc, (byte) 0x7c,
+        (byte) 0xaf, (byte) 0xc9, (byte) 0x12, (byte) 0x95, (byte) 0x3c, (byte) 0xde, (byte) 0xcb, (byte) 0x2f,
+        (byte) 0x35, (byte) 0x5a, (byte) 0x2e, (byte) 0x2c, (byte) 0x35, (byte) 0xa5, (byte) 0x0f, (byte) 0xad,
+        (byte) 0x75, (byte) 0x4c, (byte) 0xb3, (byte) 0xb2, (byte) 0x31, (byte) 0x66, (byte) 0x42, (byte) 0x4b,
+        (byte) 0xa3, (byte) 0xb6, (byte) 0xe3, (byte) 0x11, (byte) 0x2a, (byte) 0x2b, (byte) 0x89, (byte) 0x8c,
+        (byte) 0x38, (byte) 0xc5, (byte) 0xc1, (byte) 0x5e, (byte) 0xdb, (byte) 0x23, (byte) 0x86, (byte) 0x93,
+        (byte) 0x39,
+    });
+
+    /**
+     * Test data is PKCS#1 padded "Android.\n" which can be generated by:
+     * echo "Android." | openssl rsautl -inkey rsa.key -sign | openssl rsautl -inkey rsa.key -raw -verify | recode ../x1
+     */
+    private static final byte[] RSA_2048_Vector1 = new byte[] {
+        (byte) 0x00, (byte) 0x01, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+        (byte) 0x00, (byte) 0x41, (byte) 0x6E, (byte) 0x64, (byte) 0x72, (byte) 0x6F,
+        (byte) 0x69, (byte) 0x64, (byte) 0x2E, (byte) 0x0A,
+    };
+
+    /**
+     * This vector is simply "Android.\n" which is too short.
+     */
+    private static final byte[] TooShort_Vector = new byte[] {
+        (byte) 0x41, (byte) 0x6E, (byte) 0x64, (byte) 0x72, (byte) 0x6F, (byte) 0x69,
+        (byte) 0x64, (byte) 0x2E, (byte) 0x0A,
+    };
+
+    /**
+     * This vector is simply "Android.\n" padded with zeros.
+     */
+    private static final byte[] TooShort_Vector_Zero_Padded = new byte[] {
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+        (byte) 0x00, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f,
+        (byte) 0x69, (byte) 0x64, (byte) 0x2e, (byte) 0x0a,
+    };
+
+    /**
+     * openssl rsautl -raw -sign -inkey rsa.key | recode ../x1 | sed 's/0x/(byte) 0x/g'
+     */
+    private static final byte[] RSA_Vector1_Encrypt_Private = new byte[] {
+        (byte) 0x35, (byte) 0x43, (byte) 0x38, (byte) 0x44, (byte) 0xAD, (byte) 0x3F,
+        (byte) 0x97, (byte) 0x02, (byte) 0xFB, (byte) 0x59, (byte) 0x1F, (byte) 0x4A,
+        (byte) 0x2B, (byte) 0xB9, (byte) 0x06, (byte) 0xEC, (byte) 0x66, (byte) 0xE6,
+        (byte) 0xD2, (byte) 0xC5, (byte) 0x8B, (byte) 0x7B, (byte) 0xE3, (byte) 0x18,
+        (byte) 0xBF, (byte) 0x07, (byte) 0xD6, (byte) 0x01, (byte) 0xF9, (byte) 0xD9,
+        (byte) 0x89, (byte) 0xC4, (byte) 0xDB, (byte) 0x00, (byte) 0x68, (byte) 0xFF,
+        (byte) 0x9B, (byte) 0x43, (byte) 0x90, (byte) 0xF2, (byte) 0xDB, (byte) 0x83,
+        (byte) 0xF4, (byte) 0x7E, (byte) 0xC6, (byte) 0x81, (byte) 0x01, (byte) 0x3A,
+        (byte) 0x0B, (byte) 0xE5, (byte) 0xED, (byte) 0x08, (byte) 0x73, (byte) 0x3E,
+        (byte) 0xE1, (byte) 0x3F, (byte) 0xDF, (byte) 0x1F, (byte) 0x07, (byte) 0x6D,
+        (byte) 0x22, (byte) 0x8D, (byte) 0xCC, (byte) 0x4E, (byte) 0xE3, (byte) 0x9A,
+        (byte) 0xBC, (byte) 0xCC, (byte) 0x8F, (byte) 0x9E, (byte) 0x9B, (byte) 0x02,
+        (byte) 0x48, (byte) 0x00, (byte) 0xAC, (byte) 0x9F, (byte) 0xA4, (byte) 0x8F,
+        (byte) 0x87, (byte) 0xA1, (byte) 0xA8, (byte) 0xE6, (byte) 0x9D, (byte) 0xCD,
+        (byte) 0x8B, (byte) 0x05, (byte) 0xE9, (byte) 0xD2, (byte) 0x05, (byte) 0x8D,
+        (byte) 0xC9, (byte) 0x95, (byte) 0x16, (byte) 0xD0, (byte) 0xCD, (byte) 0x43,
+        (byte) 0x25, (byte) 0x8A, (byte) 0x11, (byte) 0x46, (byte) 0xD7, (byte) 0x74,
+        (byte) 0x4C, (byte) 0xCF, (byte) 0x58, (byte) 0xF9, (byte) 0xA1, (byte) 0x30,
+        (byte) 0x84, (byte) 0x52, (byte) 0xC9, (byte) 0x01, (byte) 0x5F, (byte) 0x24,
+        (byte) 0x4C, (byte) 0xB1, (byte) 0x9F, (byte) 0x7D, (byte) 0x12, (byte) 0x38,
+        (byte) 0x27, (byte) 0x0F, (byte) 0x5E, (byte) 0xFF, (byte) 0xE0, (byte) 0x55,
+        (byte) 0x8B, (byte) 0xA3, (byte) 0xAD, (byte) 0x60, (byte) 0x35, (byte) 0x83,
+        (byte) 0x58, (byte) 0xAF, (byte) 0x99, (byte) 0xDE, (byte) 0x3F, (byte) 0x5D,
+        (byte) 0x80, (byte) 0x80, (byte) 0xFF, (byte) 0x9B, (byte) 0xDE, (byte) 0x5C,
+        (byte) 0xAB, (byte) 0x97, (byte) 0x43, (byte) 0x64, (byte) 0xD9, (byte) 0x9F,
+        (byte) 0xFB, (byte) 0x67, (byte) 0x65, (byte) 0xA5, (byte) 0x99, (byte) 0xE7,
+        (byte) 0xE6, (byte) 0xEB, (byte) 0x05, (byte) 0x95, (byte) 0xFC, (byte) 0x46,
+        (byte) 0x28, (byte) 0x4B, (byte) 0xD8, (byte) 0x8C, (byte) 0xF5, (byte) 0x0A,
+        (byte) 0xEB, (byte) 0x1F, (byte) 0x30, (byte) 0xEA, (byte) 0xE7, (byte) 0x67,
+        (byte) 0x11, (byte) 0x25, (byte) 0xF0, (byte) 0x44, (byte) 0x75, (byte) 0x74,
+        (byte) 0x94, (byte) 0x06, (byte) 0x78, (byte) 0xD0, (byte) 0x21, (byte) 0xF4,
+        (byte) 0x3F, (byte) 0xC8, (byte) 0xC4, (byte) 0x4A, (byte) 0x57, (byte) 0xBE,
+        (byte) 0x02, (byte) 0x3C, (byte) 0x93, (byte) 0xF6, (byte) 0x95, (byte) 0xFB,
+        (byte) 0xD1, (byte) 0x77, (byte) 0x8B, (byte) 0x43, (byte) 0xF0, (byte) 0xB9,
+        (byte) 0x7D, (byte) 0xE0, (byte) 0x32, (byte) 0xE1, (byte) 0x72, (byte) 0xB5,
+        (byte) 0x62, (byte) 0x3F, (byte) 0x86, (byte) 0xC3, (byte) 0xD4, (byte) 0x5F,
+        (byte) 0x5E, (byte) 0x54, (byte) 0x1B, (byte) 0x5B, (byte) 0xE6, (byte) 0x74,
+        (byte) 0xA1, (byte) 0x0B, (byte) 0xE5, (byte) 0x18, (byte) 0xD2, (byte) 0x4F,
+        (byte) 0x93, (byte) 0xF3, (byte) 0x09, (byte) 0x58, (byte) 0xCE, (byte) 0xF0,
+        (byte) 0xA3, (byte) 0x61, (byte) 0xE4, (byte) 0x6E, (byte) 0x46, (byte) 0x45,
+        (byte) 0x89, (byte) 0x50, (byte) 0xBD, (byte) 0x03, (byte) 0x3F, (byte) 0x38,
+        (byte) 0xDA, (byte) 0x5D, (byte) 0xD0, (byte) 0x1B, (byte) 0x1F, (byte) 0xB1,
+        (byte) 0xEE, (byte) 0x89, (byte) 0x59, (byte) 0xC5,
+    };
+
+    private static final byte[] RSA_Vector1_ZeroPadded_Encrypted = new byte[] {
+        (byte) 0x60, (byte) 0x4a, (byte) 0x12, (byte) 0xa3, (byte) 0xa7, (byte) 0x4a,
+        (byte) 0xa4, (byte) 0xbf, (byte) 0x6c, (byte) 0x36, (byte) 0xad, (byte) 0x66,
+        (byte) 0xdf, (byte) 0xce, (byte) 0xf1, (byte) 0xe4, (byte) 0x0f, (byte) 0xd4,
+        (byte) 0x54, (byte) 0x5f, (byte) 0x03, (byte) 0x15, (byte) 0x4b, (byte) 0x9e,
+        (byte) 0xeb, (byte) 0xfe, (byte) 0x9e, (byte) 0x24, (byte) 0xce, (byte) 0x8e,
+        (byte) 0xc3, (byte) 0x36, (byte) 0xa5, (byte) 0x76, (byte) 0xf6, (byte) 0x54,
+        (byte) 0xb7, (byte) 0x84, (byte) 0x48, (byte) 0x2f, (byte) 0xd4, (byte) 0x45,
+        (byte) 0x74, (byte) 0x48, (byte) 0x5f, (byte) 0x08, (byte) 0x4e, (byte) 0x9c,
+        (byte) 0x89, (byte) 0xcc, (byte) 0x34, (byte) 0x40, (byte) 0xb1, (byte) 0x5f,
+        (byte) 0xa7, (byte) 0x0e, (byte) 0x11, (byte) 0x4b, (byte) 0xb5, (byte) 0x94,
+        (byte) 0xbe, (byte) 0x14, (byte) 0xaa, (byte) 0xaa, (byte) 0xe0, (byte) 0x38,
+        (byte) 0x1c, (byte) 0xce, (byte) 0x40, (byte) 0x61, (byte) 0xfc, (byte) 0x08,
+        (byte) 0xcb, (byte) 0x14, (byte) 0x2b, (byte) 0xa6, (byte) 0x54, (byte) 0xdf,
+        (byte) 0x05, (byte) 0x5c, (byte) 0x9b, (byte) 0x4f, (byte) 0x14, (byte) 0x93,
+        (byte) 0xb0, (byte) 0x70, (byte) 0xd9, (byte) 0x32, (byte) 0xdc, (byte) 0x24,
+        (byte) 0xe0, (byte) 0xae, (byte) 0x48, (byte) 0xfc, (byte) 0x53, (byte) 0xee,
+        (byte) 0x7c, (byte) 0x9f, (byte) 0x69, (byte) 0x34, (byte) 0xf4, (byte) 0x76,
+        (byte) 0xee, (byte) 0x67, (byte) 0xb2, (byte) 0xa7, (byte) 0x33, (byte) 0x1c,
+        (byte) 0x47, (byte) 0xff, (byte) 0x5c, (byte) 0xf0, (byte) 0xb8, (byte) 0x04,
+        (byte) 0x2c, (byte) 0xfd, (byte) 0xe2, (byte) 0xb1, (byte) 0x4a, (byte) 0x0a,
+        (byte) 0x69, (byte) 0x1c, (byte) 0x80, (byte) 0x2b, (byte) 0xb4, (byte) 0x50,
+        (byte) 0x65, (byte) 0x5c, (byte) 0x76, (byte) 0x78, (byte) 0x9a, (byte) 0x0c,
+        (byte) 0x05, (byte) 0x62, (byte) 0xf0, (byte) 0xc4, (byte) 0x1c, (byte) 0x38,
+        (byte) 0x15, (byte) 0xd0, (byte) 0xe2, (byte) 0x5a, (byte) 0x3d, (byte) 0xb6,
+        (byte) 0xe0, (byte) 0x88, (byte) 0x85, (byte) 0xd1, (byte) 0x4f, (byte) 0x7e,
+        (byte) 0xfc, (byte) 0x77, (byte) 0x0d, (byte) 0x2a, (byte) 0x45, (byte) 0xd5,
+        (byte) 0xf8, (byte) 0x3c, (byte) 0x7b, (byte) 0x2d, (byte) 0x1b, (byte) 0x82,
+        (byte) 0xfe, (byte) 0x58, (byte) 0x22, (byte) 0x47, (byte) 0x06, (byte) 0x58,
+        (byte) 0x8b, (byte) 0x4f, (byte) 0xfb, (byte) 0x9b, (byte) 0x1c, (byte) 0x70,
+        (byte) 0x36, (byte) 0x12, (byte) 0x04, (byte) 0x17, (byte) 0x47, (byte) 0x8a,
+        (byte) 0x0a, (byte) 0xec, (byte) 0x12, (byte) 0x3b, (byte) 0xf8, (byte) 0xd2,
+        (byte) 0xdc, (byte) 0x3c, (byte) 0xc8, (byte) 0x46, (byte) 0xc6, (byte) 0x51,
+        (byte) 0x06, (byte) 0x06, (byte) 0xcb, (byte) 0x84, (byte) 0x67, (byte) 0xb5,
+        (byte) 0x68, (byte) 0xd9, (byte) 0x9c, (byte) 0xd4, (byte) 0x16, (byte) 0x5c,
+        (byte) 0xb4, (byte) 0xe2, (byte) 0x55, (byte) 0xe6, (byte) 0x3a, (byte) 0x73,
+        (byte) 0x01, (byte) 0x1d, (byte) 0x6f, (byte) 0x30, (byte) 0x31, (byte) 0x59,
+        (byte) 0x8b, (byte) 0x2f, (byte) 0x4c, (byte) 0xe7, (byte) 0x86, (byte) 0x4c,
+        (byte) 0x39, (byte) 0x4e, (byte) 0x67, (byte) 0x3b, (byte) 0x22, (byte) 0x9b,
+        (byte) 0x85, (byte) 0x5a, (byte) 0xc3, (byte) 0x29, (byte) 0xaf, (byte) 0x8c,
+        (byte) 0x7c, (byte) 0x59, (byte) 0x4a, (byte) 0x24, (byte) 0xfa, (byte) 0xba,
+        (byte) 0x55, (byte) 0x40, (byte) 0x13, (byte) 0x64, (byte) 0xd8, (byte) 0xcb,
+        (byte) 0x4b, (byte) 0x98, (byte) 0x3f, (byte) 0xae, (byte) 0x20, (byte) 0xfd,
+        (byte) 0x8a, (byte) 0x50, (byte) 0x73, (byte) 0xe4,
+    };
+
+    public void testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+
+        final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually decrypting with private keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        byte[] encrypted = c.doFinal(RSA_2048_Vector1);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, privKey);
+        encrypted = c.doFinal(RSA_2048_Vector1);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+
+        final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually decrypting with private keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        c.update(RSA_2048_Vector1);
+        byte[] encrypted = c.doFinal();
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, privKey);
+        c.update(RSA_2048_Vector1);
+        encrypted = c.doFinal();
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success()
+            throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+
+        final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually decrypting with private keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        int i;
+        for (i = 0; i < RSA_2048_Vector1.length / 2; i++) {
+            c.update(RSA_2048_Vector1, i, 1);
+        }
+        byte[] encrypted = c.doFinal(RSA_2048_Vector1, i, RSA_2048_Vector1.length - i);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, privKey);
+        for (i = 0; i < RSA_2048_Vector1.length / 2; i++) {
+            c.update(RSA_2048_Vector1, i, 1);
+        }
+        encrypted = c.doFinal(RSA_2048_Vector1, i, RSA_2048_Vector1.length - i);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+        final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually decrypting with private keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        byte[] encrypted = new byte[RSA_Vector1_Encrypt_Private.length];
+        final int encryptLen = c
+                .doFinal(RSA_2048_Vector1, 0, RSA_2048_Vector1.length, encrypted, 0);
+        assertEquals("Encrypted size should match expected", RSA_Vector1_Encrypt_Private.length,
+                encryptLen);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, privKey);
+        final int decryptLen = c
+                .doFinal(RSA_2048_Vector1, 0, RSA_2048_Vector1.length, encrypted, 0);
+        assertEquals("Encrypted size should match expected", RSA_Vector1_Encrypt_Private.length,
+                decryptLen);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_Encrypt_Private, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+
+        final PublicKey privKey = kf.generatePublic(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually encrypting with public keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_2048_Vector1, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, privKey);
+        encrypted = c.doFinal(RSA_Vector1_Encrypt_Private);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_2048_Vector1, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+
+        final PublicKey pubKey = kf.generatePublic(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually encrypting with public keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, pubKey);
+        byte[] encrypted = new byte[RSA_2048_Vector1.length];
+        final int encryptLen = c.doFinal(RSA_Vector1_Encrypt_Private, 0,
+                RSA_Vector1_Encrypt_Private.length, encrypted, 0);
+        assertEquals("Encrypted size should match expected", RSA_2048_Vector1.length, encryptLen);
+        assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, pubKey);
+        final int decryptLen = c.doFinal(RSA_Vector1_Encrypt_Private, 0,
+                RSA_Vector1_Encrypt_Private.length, encrypted, 0);
+        assertEquals("Encrypted size should match expected", RSA_2048_Vector1.length, decryptLen);
+        assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+
+        final PublicKey privKey = kf.generatePublic(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually encrypting with public keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        c.update(RSA_Vector1_Encrypt_Private);
+        byte[] encrypted = c.doFinal();
+        assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, privKey);
+        c.update(RSA_Vector1_Encrypt_Private);
+        encrypted = c.doFinal();
+        assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success()
+            throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+
+        final PublicKey privKey = kf.generatePublic(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually encrypting with public keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        int i;
+        for (i = 0; i < RSA_Vector1_Encrypt_Private.length / 2; i++) {
+            c.update(RSA_Vector1_Encrypt_Private, i, 1);
+        }
+        byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private, i, RSA_2048_Vector1.length - i);
+        assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, privKey);
+        for (i = 0; i < RSA_Vector1_Encrypt_Private.length / 2; i++) {
+            c.update(RSA_Vector1_Encrypt_Private, i, 1);
+        }
+        encrypted = c.doFinal(RSA_Vector1_Encrypt_Private, i, RSA_2048_Vector1.length - i);
+        assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Public_TooSmall_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+
+        final PublicKey privKey = kf.generatePublic(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually encrypting with public keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        byte[] encrypted = c.doFinal(TooShort_Vector);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_ZeroPadded_Encrypted, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, privKey);
+        encrypted = c.doFinal(TooShort_Vector);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(RSA_Vector1_ZeroPadded_Encrypted, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Private_TooSmall_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+
+        final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually encrypting with public keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        byte[] encrypted = c.doFinal(RSA_Vector1_ZeroPadded_Encrypted);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(TooShort_Vector_Zero_Padded, encrypted));
+
+        c.init(Cipher.DECRYPT_MODE, privKey);
+        encrypted = c.doFinal(RSA_Vector1_ZeroPadded_Encrypted);
+        assertTrue("Encrypted should match expected",
+                Arrays.equals(TooShort_Vector_Zero_Padded, encrypted));
+    }
+
+    public void testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure()
+            throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+
+        final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually encrypting with public keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+        c.update(RSA_Vector1_ZeroPadded_Encrypted);
+
+        try {
+            c.doFinal(RSA_Vector1_ZeroPadded_Encrypted);
+            fail("Should have error when block size is too big.");
+        } catch (IllegalBlockSizeException success) {
+        }
+    }
+
+    public void testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure()
+            throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+
+        final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually encrypting with public keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+
+        byte[] output = new byte[RSA_2048_Vector1.length];
+        c.update(RSA_Vector1_ZeroPadded_Encrypted, 0, RSA_Vector1_ZeroPadded_Encrypted.length,
+                output);
+
+        try {
+            c.doFinal(RSA_Vector1_ZeroPadded_Encrypted);
+            fail("Should have error when block size is too big.");
+        } catch (IllegalBlockSizeException success) {
+        }
+    }
+
+    public void testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+                RSA_2048_privateExponent);
+
+        final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+
+        /*
+         * You're actually encrypting with public keys, but there is no
+         * distinction made here. It's all keyed off of what kind of key you're
+         * using. ENCRYPT_MODE and DECRYPT_MODE are the same.
+         */
+        c.init(Cipher.ENCRYPT_MODE, privKey);
+
+        byte[] tooBig_Vector = new byte[RSA_Vector1_ZeroPadded_Encrypted.length * 2];
+        System.arraycopy(RSA_Vector1_ZeroPadded_Encrypted, 0, tooBig_Vector, 0,
+                RSA_Vector1_ZeroPadded_Encrypted.length);
+        System.arraycopy(RSA_Vector1_ZeroPadded_Encrypted, 0, tooBig_Vector,
+                RSA_Vector1_ZeroPadded_Encrypted.length, RSA_Vector1_ZeroPadded_Encrypted.length);
+
+        try {
+            c.doFinal(tooBig_Vector);
+            fail("Should have error when block size is too big.");
+        } catch (IllegalBlockSizeException success) {
+        }
+    }
+
+    public void testRSA_ECB_NoPadding_GetBlockSize_Success() throws Exception {
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+        assertEquals("RSA is not a block cipher and should return block size of 0",
+                0, c.getBlockSize());
+
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        final PublicKey pubKey = kf.generatePublic(pubKeySpec);
+        c.init(Cipher.ENCRYPT_MODE, pubKey);
+
+        assertEquals("RSA is not a block cipher and should return block size of 0",
+                0, c.getBlockSize());
+    }
+
+    public void testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure() throws Exception {
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+        try {
+            c.getOutputSize(RSA_2048_Vector1.length);
+            fail("Should throw IllegalStateException if getOutputSize is called before init");
+        } catch (IllegalStateException success) {
+        }
+    }
+
+    public void testRSA_ECB_NoPadding_GetOutputSize_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        final PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+        c.init(Cipher.ENCRYPT_MODE, pubKey);
+
+        final int modulusInBytes = RSA_2048_modulus.bitLength() / 8;
+        assertEquals("Output size should be equal to modulus size",
+                modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length));
+
+        assertEquals("Output size should be equal to modulus size",
+                modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length * 2));
+
+        assertEquals("Output size should be equal to modulus size",
+                modulusInBytes, c.getOutputSize(0));
+    }
+
+    public void testRSA_ECB_NoPadding_GetIV_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        final PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+        assertNull("ECB mode has no IV and should be null", c.getIV());
+
+        c.init(Cipher.ENCRYPT_MODE, pubKey);
+
+        assertNull("ECB mode has no IV and should be null", c.getIV());
+    }
+
+    public void testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success() throws Exception {
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+                RSA_2048_publicExponent);
+        final PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+        Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
+        assertNull("Parameters should be null", c.getParameters());
+    }
 }
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
index e3ae16f..65d8690 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
@@ -347,6 +347,51 @@
         c.close();
     }
 
+   /**
+    * http://code.google.com/p/android/issues/detail?id=31903
+    * This test case directly tests the fix for the issue.
+    */
+    public void test_SSLEngine_clientAuthWantedNoClientCert() throws Exception {
+        TestSSLContext clientAuthContext
+                = TestSSLContext.create(TestKeyStore.getClient(),
+                                        TestKeyStore.getServer());
+        TestSSLEnginePair p = TestSSLEnginePair.create(clientAuthContext,
+                                                       new TestSSLEnginePair.Hooks() {
+            @Override
+            void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+                server.setWantClientAuth(true);
+            }
+        });
+        assertConnected(p);
+        clientAuthContext.close();
+    }
+
+   /**
+    * http://code.google.com/p/android/issues/detail?id=31903
+    * This test case verifies that if the server requires a client cert
+    * (setNeedClientAuth) but the client does not provide one SSL connection
+    * establishment will fail
+    */
+    public void test_SSLEngine_clientAuthNeededNoClientCert() throws Exception {
+        boolean handshakeExceptionCaught = false;
+        TestSSLContext clientAuthContext
+                = TestSSLContext.create(TestKeyStore.getClient(),
+                                        TestKeyStore.getServer());
+        try {
+            TestSSLEnginePair.create(clientAuthContext,
+                             new TestSSLEnginePair.Hooks() {
+                @Override
+                void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+                    server.setNeedClientAuth(true);
+                }
+            });
+            fail();
+        } catch (SSLHandshakeException expected) {
+        } finally {
+            clientAuthContext.close();
+        }
+    }
+
     public void test_SSLEngine_getEnableSessionCreation() throws Exception {
         TestSSLContext c = TestSSLContext.create();
         SSLEngine e = c.clientContext.createSSLEngine();
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 90cdeb9..8c9239e 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -16,6 +16,7 @@
 
 package libcore.javax.net.ssl;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.ServerSocket;
@@ -30,6 +31,10 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import javax.net.ssl.HandshakeCompletedEvent;
 import javax.net.ssl.HandshakeCompletedListener;
 import javax.net.ssl.KeyManager;
@@ -38,7 +43,6 @@
 import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLParameters;
 import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLProtocolException;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
@@ -271,32 +275,28 @@
         SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
                                                                                        c.port);
         final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                server.startHandshake();
+                assertNotNull(server.getSession());
                 try {
-                    server.startHandshake();
-                    assertNotNull(server.getSession());
-                    try {
-                        server.getSession().getPeerCertificates();
-                        fail();
-                    } catch (SSLPeerUnverifiedException expected) {
-                    }
-                    Certificate[] localCertificates = server.getSession().getLocalCertificates();
-                    assertNotNull(localCertificates);
-                    TestKeyStore.assertChainLength(localCertificates);
-                    assertNotNull(localCertificates[0]);
-                    TestSSLContext.assertServerCertificateChain(c.serverTrustManager,
-                                                                localCertificates);
-                    TestSSLContext.assertCertificateInKeyStore(localCertificates[0],
-                                                               c.serverKeyStore);
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
+                    server.getSession().getPeerCertificates();
+                    fail();
+                } catch (SSLPeerUnverifiedException expected) {
                 }
+                Certificate[] localCertificates = server.getSession().getLocalCertificates();
+                assertNotNull(localCertificates);
+                TestKeyStore.assertChainLength(localCertificates);
+                assertNotNull(localCertificates[0]);
+                TestSSLContext.assertServerCertificateChain(c.serverTrustManager,
+                                                            localCertificates);
+                TestSSLContext.assertCertificateInKeyStore(localCertificates[0],
+                                                           c.serverKeyStore);
+                return null;
             }
         });
-        thread.start();
+        executor.shutdown();
         client.startHandshake();
         assertNotNull(client.getSession());
         assertNull(client.getSession().getLocalCertificates());
@@ -307,7 +307,7 @@
         TestSSLContext.assertServerCertificateChain(c.clientTrustManager,
                                                     peerCertificates);
         TestSSLContext.assertCertificateInKeyStore(peerCertificates[0], c.serverKeyStore);
-        thread.join();
+        future.get();
         client.close();
         server.close();
         c.close();
@@ -321,25 +321,24 @@
         // RI used to throw SSLException on accept, now throws on startHandshake
         if (StandardNames.IS_RI) {
             final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-            Thread thread = new Thread(new Runnable () {
-                public void run() {
+            ExecutorService executor = Executors.newSingleThreadExecutor();
+            Future<Void> future = executor.submit(new Callable<Void>() {
+                @Override public Void call() throws Exception {
                     try {
                         server.startHandshake();
+                        fail();
                     } catch (SSLHandshakeException expected) {
-                    } catch (RuntimeException e) {
-                        throw e;
-                    } catch (Exception e) {
-                        throw new RuntimeException(e);
                     }
+                    return null;
                 }
             });
-            thread.start();
+            executor.shutdown();
             try {
                 client.startHandshake();
                 fail();
             } catch (SSLHandshakeException expected) {
             }
-            thread.join();
+            future.get();
             server.close();
         } else {
             try {
@@ -359,20 +358,16 @@
         SSLSocket client = (SSLSocket)
             clientContext.getSocketFactory().createSocket(c.host, c.port);
         final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
-                try {
-                    server.startHandshake();
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                server.startHandshake();
+                return null;
             }
         });
-        thread.start();
+        executor.shutdown();
         client.startHandshake();
-        thread.join();
+        future.get();
         client.close();
         server.close();
         c.close();
@@ -383,18 +378,14 @@
         final SSLSocket client = (SSLSocket)
                 c.clientContext.getSocketFactory().createSocket(c.host, c.port);
         final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
-                try {
-                    server.startHandshake();
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                server.startHandshake();
+                return null;
             }
         });
-        thread.start();
+        executor.shutdown();
         final boolean[] handshakeCompletedListenerCalled = new boolean[1];
         client.addHandshakeCompletedListener(new HandshakeCompletedListener() {
             public void handshakeCompleted(HandshakeCompletedEvent event) {
@@ -472,7 +463,7 @@
             }
         });
         client.startHandshake();
-        thread.join();
+        future.get();
         if (!TestSSLContext.sslServerSocketSupportsSessionTickets()) {
             assertNotNull(c.serverContext.getServerSessionContext().getSession(
                     client.getSession().getId()));
@@ -492,25 +483,21 @@
         final SSLSocket client = (SSLSocket)
                 c.clientContext.getSocketFactory().createSocket(c.host, c.port);
         final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
-                try {
-                    server.startHandshake();
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                server.startHandshake();
+                return null;
             }
         });
-        thread.start();
+        executor.shutdown();
         client.addHandshakeCompletedListener(new HandshakeCompletedListener() {
             public void handshakeCompleted(HandshakeCompletedEvent event) {
                 throw new RuntimeException("RuntimeException from handshakeCompleted");
             }
         });
         client.startHandshake();
-        thread.join();
+        future.get();
         client.close();
         server.close();
         c.close();
@@ -551,6 +538,46 @@
         }
     }
 
+    private void test_SSLSocket_setUseClientMode(final boolean clientClientMode,
+                                                 final boolean serverClientMode)
+            throws Exception {
+        TestSSLContext c = TestSSLContext.create();
+        SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+                                                                                       c.port);
+        final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<IOException> future = executor.submit(new Callable<IOException>() {
+            @Override public IOException call() throws Exception {
+                try {
+                    if (!serverClientMode) {
+                        server.setSoTimeout(1 * 1000);
+                    }
+                    server.setUseClientMode(serverClientMode);
+                    server.startHandshake();
+                    return null;
+                } catch (SSLHandshakeException e) {
+                    return e;
+                } catch (SocketTimeoutException e) {
+                    return e;
+                }
+            }
+        });
+        executor.shutdown();
+        if (!clientClientMode) {
+            client.setSoTimeout(1 * 1000);
+        }
+        client.setUseClientMode(clientClientMode);
+        client.startHandshake();
+        IOException ioe = future.get();
+        if (ioe != null) {
+            throw ioe;
+        }
+        client.close();
+        server.close();
+        c.close();
+    }
+
     public void test_SSLSocket_setUseClientMode_afterHandshake() throws Exception {
 
         // can't set after handshake
@@ -567,72 +594,25 @@
         }
     }
 
-    private void test_SSLSocket_setUseClientMode(final boolean clientClientMode,
-                                                 final boolean serverClientMode)
-            throws Exception {
-        TestSSLContext c = TestSSLContext.create();
-        SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
-                                                                                       c.port);
-        final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-
-        final SSLHandshakeException[] sslHandshakeException = new SSLHandshakeException[1];
-        final SocketTimeoutException[] socketTimeoutException = new SocketTimeoutException[1];
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
-                try {
-                    if (!serverClientMode) {
-                        server.setSoTimeout(1 * 1000);
-                    }
-                    server.setUseClientMode(serverClientMode);
-                    server.startHandshake();
-                } catch (SSLHandshakeException e) {
-                    sslHandshakeException[0] = e;
-                } catch (SocketTimeoutException e) {
-                    socketTimeoutException[0] = e;
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        });
-        thread.start();
-        if (!clientClientMode) {
-            client.setSoTimeout(1 * 1000);
-        }
-        client.setUseClientMode(clientClientMode);
-        client.startHandshake();
-        thread.join();
-        if (sslHandshakeException[0] != null) {
-            throw sslHandshakeException[0];
-        }
-        if (socketTimeoutException[0] != null) {
-            throw socketTimeoutException[0];
-        }
-        client.close();
-        server.close();
-        c.close();
-    }
-
     public void test_SSLSocket_untrustedServer() throws Exception {
         TestSSLContext c = TestSSLContext.create(TestKeyStore.getClientCA2(),
                                                  TestKeyStore.getServer());
         SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
                                                                                        c.port);
         final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
                 try {
                     server.startHandshake();
+                    assertFalse(StandardNames.IS_RI);
                 } catch (SSLHandshakeException expected) {
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
+                    assertTrue(StandardNames.IS_RI);
                 }
+                return null;
             }
         });
-        thread.start();
+        executor.shutdown();
         try {
             client.startHandshake();
             fail();
@@ -641,7 +621,7 @@
         }
         client.close();
         server.close();
-        thread.join();
+        future.get();
     }
 
     public void test_SSLSocket_clientAuth() throws Exception {
@@ -650,43 +630,38 @@
         SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
                                                                                        c.port);
         final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
-                try {
-                    assertFalse(server.getWantClientAuth());
-                    assertFalse(server.getNeedClientAuth());
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                assertFalse(server.getWantClientAuth());
+                assertFalse(server.getNeedClientAuth());
 
-                    // confirm turning one on by itself
-                    server.setWantClientAuth(true);
-                    assertTrue(server.getWantClientAuth());
-                    assertFalse(server.getNeedClientAuth());
+                // confirm turning one on by itself
+                server.setWantClientAuth(true);
+                assertTrue(server.getWantClientAuth());
+                assertFalse(server.getNeedClientAuth());
 
-                    // confirm turning setting on toggles the other
-                    server.setNeedClientAuth(true);
-                    assertFalse(server.getWantClientAuth());
-                    assertTrue(server.getNeedClientAuth());
+                // confirm turning setting on toggles the other
+                server.setNeedClientAuth(true);
+                assertFalse(server.getWantClientAuth());
+                assertTrue(server.getNeedClientAuth());
 
-                    // confirm toggling back
-                    server.setWantClientAuth(true);
-                    assertTrue(server.getWantClientAuth());
-                    assertFalse(server.getNeedClientAuth());
+                // confirm toggling back
+                server.setWantClientAuth(true);
+                assertTrue(server.getWantClientAuth());
+                assertFalse(server.getNeedClientAuth());
 
-                    server.startHandshake();
-
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
+                server.startHandshake();
+                return null;
             }
         });
-        thread.start();
+        executor.shutdown();
         client.startHandshake();
         assertNotNull(client.getSession().getLocalCertificates());
         TestKeyStore.assertChainLength(client.getSession().getLocalCertificates());
         TestSSLContext.assertClientCertificateChain(c.clientTrustManager,
                                                     client.getSession().getLocalCertificates());
-        thread.join();
+        future.get();
         client.close();
         server.close();
         c.close();
@@ -727,22 +702,20 @@
         SSLSocket client = (SSLSocket) clientContext.getSocketFactory().createSocket(c.host,
                                                                                      c.port);
         final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
                 try {
                     server.setNeedClientAuth(true);
                     server.startHandshake();
                     fail();
                 } catch (SSLHandshakeException expected) {
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
                 }
+                return null;
             }
         });
 
-        thread.start();
+        executor.shutdown();
         try {
             client.startHandshake();
             fail();
@@ -750,7 +723,7 @@
             // before we would get a NullPointerException from passing
             // due to the null PrivateKey return by the X509KeyManager.
         }
-        thread.join();
+        future.get();
         client.close();
         server.close();
         c.close();
@@ -773,29 +746,25 @@
         SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
                                                                                        c.port);
         final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                server.setEnableSessionCreation(false);
                 try {
-                    server.setEnableSessionCreation(false);
-                    try {
-                        server.startHandshake();
-                        fail();
-                    } catch (SSLException expected) {
-                    }
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
+                    server.startHandshake();
+                    fail();
+                } catch (SSLException expected) {
                 }
+                return null;
             }
         });
-        thread.start();
+        executor.shutdown();
         try {
             client.startHandshake();
             fail();
         } catch (SSLException expected) {
         }
-        thread.join();
+        future.get();
         client.close();
         server.close();
         c.close();
@@ -806,29 +775,25 @@
         SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
                                                                                        c.port);
         final SSLSocket server = (SSLSocket) c.serverSocket.accept();
-        Thread thread = new Thread(new Runnable () {
-            public void run() {
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
                 try {
-                    try {
-                        server.startHandshake();
-                        fail();
-                    } catch (SSLException expected) {
-                    }
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
+                    server.startHandshake();
+                    fail();
+                } catch (SSLException expected) {
                 }
+                return null;
             }
         });
-        thread.start();
+        executor.shutdown();
         client.setEnableSessionCreation(false);
         try {
             client.startHandshake();
             fail();
         } catch (SSLException expected) {
         }
-        thread.join();
+        future.get();
         client.close();
         server.close();
         c.close();
@@ -1012,32 +977,25 @@
                                                                 c.host.getHostName(),
                                                                 c.port,
                                                                 false);
-        Thread clientThread = new Thread(new Runnable () {
-            public void run() {
-                try {
-                    try {
-                        wrapping.startHandshake();
-                        wrapping.getOutputStream().write(42);
-                        // close the underlying socket,
-                        // so that no SSL shutdown is sent
-                        underlying.close();
-                        wrapping.close();
-                    } catch (SSLException expected) {
-                    }
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> clientFuture = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                wrapping.startHandshake();
+                wrapping.getOutputStream().write(42);
+                // close the underlying socket,
+                // so that no SSL shutdown is sent
+                underlying.close();
+                wrapping.close();
+                return null;
             }
         });
-        clientThread.start();
+        executor.shutdown();
 
         SSLSocket server = (SSLSocket) c.serverSocket.accept();
         server.startHandshake();
         server.getInputStream().read();
         // wait for thread to finish so we know client is closed.
-        clientThread.join();
+        clientFuture.get();
         // close should cause an SSL_shutdown which will fail
         // because the peer has closed, but it shouldn't throw.
         server.close();
@@ -1054,9 +1012,10 @@
         assertEquals(0, wrapping.getSoTimeout());
 
         // setting wrapper sets underlying and ...
-        wrapping.setSoTimeout(10);
-        assertEquals(10, wrapping.getSoTimeout());
-        assertEquals(10, underlying.getSoTimeout());
+        int expectedTimeoutMillis = 1000;  // Using a small value such as 10 was affected by rounding
+        wrapping.setSoTimeout(expectedTimeoutMillis);
+        assertEquals(expectedTimeoutMillis, wrapping.getSoTimeout());
+        assertEquals(expectedTimeoutMillis, underlying.getSoTimeout());
 
         // ... getting wrapper inspects underlying
         underlying.setSoTimeout(0);
@@ -1126,17 +1085,15 @@
 
     private void test_SSLSocket_interrupt_case(Socket toRead, final Socket toClose)
             throws Exception {
-        new Thread() {
-            @Override
-            public void run() {
-                try {
-                    Thread.sleep(1 * 1000);
-                    toClose.close();
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> future = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                Thread.sleep(1 * 1000);
+                toClose.close();
+                return null;
             }
-        }.start();
+        });
+        executor.shutdown();
         try {
             toRead.setSoTimeout(5 * 1000);
             toRead.getInputStream().read();
@@ -1145,6 +1102,43 @@
             throw e;
         } catch (SocketException expected) {
         }
+        future.get();
+    }
+
+    /**
+     * b/7014266 Test to confirm that an SSLSocket.close() on one
+     * thread will interupt another thread blocked reading on the same
+     * socket.
+     */
+    public void test_SSLSocket_interrupt_read() throws Exception {
+        TestSSLContext c = TestSSLContext.create();
+        final Socket underlying = new Socket(c.host, c.port);
+        final SSLSocket wrapping = (SSLSocket)
+                c.clientContext.getSocketFactory().createSocket(underlying,
+                                                                c.host.getHostName(),
+                                                                c.port,
+                                                                false);
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        Future<Void> clientFuture = executor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                try {
+                    wrapping.startHandshake();
+                    assertFalse(StandardNames.IS_RI);
+                    wrapping.setSoTimeout(5 * 1000);
+                    assertEquals(-1, wrapping.getInputStream().read());
+                } catch (Exception e) {
+                    assertTrue(StandardNames.IS_RI);
+                }
+                return null;
+            }
+        });
+        executor.shutdown();
+
+        SSLSocket server = (SSLSocket) c.serverSocket.accept();
+        server.startHandshake();
+        wrapping.close();
+        clientFuture.get();
+        server.close();
     }
 
     public void test_TestSSLSocketPair_create() {
diff --git a/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java b/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java
index 360ca44..133924e 100644
--- a/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java
+++ b/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java
@@ -959,7 +959,7 @@
 
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
         connection.addRequestProperty("Cache-Control", "only-if-cached");
-        assertBadGateway(connection);
+        assertGatewayTimeout(connection);
     }
 
     public void testRequestOnlyIfCachedWithFullResponseCached() throws IOException {
@@ -983,7 +983,7 @@
         assertEquals("A", readAscii(server.getUrl("/").openConnection()));
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
         connection.addRequestProperty("Cache-Control", "only-if-cached");
-        assertBadGateway(connection);
+        assertGatewayTimeout(connection);
     }
 
     public void testRequestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException {
@@ -993,7 +993,7 @@
         assertEquals("A", readAscii(server.getUrl("/").openConnection()));
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
         connection.addRequestProperty("Cache-Control", "only-if-cached");
-        assertBadGateway(connection);
+        assertGatewayTimeout(connection);
     }
 
     public void testRequestCacheControlNoCache() throws Exception {
@@ -1804,13 +1804,13 @@
         }
     }
 
-    private void assertBadGateway(HttpURLConnection connection) throws IOException {
+    private void assertGatewayTimeout(HttpURLConnection connection) throws IOException {
         try {
             connection.getInputStream();
             fail();
         } catch (FileNotFoundException expected) {
         }
-        assertEquals(HttpURLConnection.HTTP_BAD_GATEWAY, connection.getResponseCode());
+        assertEquals(504, connection.getResponseCode());
         assertEquals(-1, connection.getErrorStream().read());
     }
 
diff --git a/luni/src/test/java/libcore/xml/DomSerializationTest.java b/luni/src/test/java/libcore/xml/DomSerializationTest.java
new file mode 100644
index 0000000..9015f97
--- /dev/null
+++ b/luni/src/test/java/libcore/xml/DomSerializationTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.xml;
+
+import java.io.StringWriter;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import junit.framework.TestCase;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public final class DomSerializationTest extends TestCase {
+    private DocumentBuilder documentBuilder;
+    private Transformer transformer;
+
+    @Override protected void setUp() throws Exception {
+        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+        documentBuilder = builderFactory.newDocumentBuilder();
+        transformer = TransformerFactory.newInstance().newTransformer();
+    }
+
+    public void testWriteDocument() throws Exception {
+        Document document = documentBuilder.newDocument();
+        Element foo = document.createElement("foo");
+        Attr quux = document.createAttribute("quux");
+        quux.setValue("abc");
+        foo.setAttributeNode(quux);
+        foo.appendChild(document.createElement("bar"));
+        foo.appendChild(document.createElement("baz"));
+        document.appendChild(foo);
+        assertXmlEquals("<foo quux=\"abc\"><bar/><baz/></foo>", document);
+    }
+
+    public void testWriteSpecialCharactersInText() throws Exception {
+        Document document = documentBuilder.newDocument();
+        Element foo = document.createElement("foo");
+        foo.appendChild(document.createTextNode("5'8\", 5 < 6 & 7 > 3!"));
+        document.appendChild(foo);
+        assertXmlEquals("<foo>5'8\", 5 &lt; 6 &amp; 7 &gt; 3!</foo>", document);
+    }
+
+    private String toXml(Document document) throws Exception {
+        StringWriter stringWriter = new StringWriter();
+        transformer.transform(new DOMSource(document), new StreamResult(stringWriter));
+        return stringWriter.toString();
+    }
+
+    private void assertXmlEquals(String expectedXml, Document document) throws Exception {
+        String actual = toXml(document);
+        String declarationA = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+        String declarationB = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>";
+        assertTrue(actual, actual.equals(declarationA + expectedXml)
+                || actual.equals(declarationB + expectedXml));
+    }
+}
diff --git a/xml/src/test/java/org/kxml2/io/KXmlSerializerTest.java b/luni/src/test/java/libcore/xml/KxmlSerializerTest.java
similarity index 63%
rename from xml/src/test/java/org/kxml2/io/KXmlSerializerTest.java
rename to luni/src/test/java/libcore/xml/KxmlSerializerTest.java
index 7aba746..6a75a9b 100644
--- a/xml/src/test/java/org/kxml2/io/KXmlSerializerTest.java
+++ b/luni/src/test/java/libcore/xml/KxmlSerializerTest.java
@@ -14,26 +14,69 @@
  * limitations under the License.
  */
 
-package org.kxml2.io;
-
-import junit.framework.TestCase;
+package libcore.xml;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.StringWriter;
+import junit.framework.TestCase;
+import org.kxml2.io.KXmlSerializer;
 import org.w3c.dom.Document;
 import org.w3c.dom.NodeList;
 import org.xmlpull.v1.XmlSerializer;
+import static tests.support.Support_Xml.domOf;
 
-import static tests.support.Support_Xml.*;
-
-public class KXmlSerializerTest extends TestCase {
+public final class KxmlSerializerTest extends TestCase {
     private static final String NAMESPACE = null;
 
-    private static boolean isValidXmlCodePoint(int c) {
-        // http://www.w3.org/TR/REC-xml/#charsets
-        return (c >= 0x20 && c <= 0xd7ff) || (c == 0x9) || (c == 0xa) || (c == 0xd) ||
-                (c >= 0xe000 && c <= 0xfffd) || (c >= 0x10000 && c <= 0x10ffff);
+    public void testWhitespaceInAttributeValue() throws Exception {
+        StringWriter stringWriter = new StringWriter();
+        XmlSerializer serializer = new KXmlSerializer();
+        serializer.setOutput(stringWriter);
+        serializer.startDocument("UTF-8", null);
+        serializer.startTag(NAMESPACE, "a");
+        serializer.attribute(NAMESPACE, "cr", "\r");
+        serializer.attribute(NAMESPACE, "lf", "\n");
+        serializer.attribute(NAMESPACE, "tab", "\t");
+        serializer.attribute(NAMESPACE, "space", " ");
+        serializer.endTag(NAMESPACE, "a");
+        serializer.endDocument();
+        assertXmlEquals("<a cr=\"&#13;\" lf=\"&#10;\" tab=\"&#9;\" space=\" \" />",
+                stringWriter.toString());
+    }
+
+    public void testWriteDocument() throws Exception {
+        StringWriter stringWriter = new StringWriter();
+        XmlSerializer serializer = new KXmlSerializer();
+        serializer.setOutput(stringWriter);
+        serializer.startDocument("UTF-8", null);
+        serializer.startTag(NAMESPACE, "foo");
+        serializer.attribute(NAMESPACE, "quux", "abc");
+        serializer.startTag(NAMESPACE, "bar");
+        serializer.endTag(NAMESPACE, "bar");
+        serializer.startTag(NAMESPACE, "baz");
+        serializer.endTag(NAMESPACE, "baz");
+        serializer.endTag(NAMESPACE, "foo");
+        serializer.endDocument();
+        assertXmlEquals("<foo quux=\"abc\"><bar /><baz /></foo>", stringWriter.toString());
+    }
+
+    // http://code.google.com/p/android/issues/detail?id=21250
+    public void testWriteSpecialCharactersInText() throws Exception {
+        StringWriter stringWriter = new StringWriter();
+        XmlSerializer serializer = new KXmlSerializer();
+        serializer.setOutput(stringWriter);
+        serializer.startDocument("UTF-8", null);
+        serializer.startTag(NAMESPACE, "foo");
+        serializer.text("5'8\", 5 < 6 & 7 > 3!");
+        serializer.endTag(NAMESPACE, "foo");
+        serializer.endDocument();
+        assertXmlEquals("<foo>5'8\", 5 &lt; 6 &amp; 7 &gt; 3!</foo>", stringWriter.toString());
+    }
+
+    private void assertXmlEquals(String expectedXml, String actualXml) throws Exception {
+        String declaration = "<?xml version='1.0' encoding='UTF-8' ?>";
+        assertEquals(declaration + expectedXml, actualXml);
     }
 
     private static XmlSerializer newSerializer() throws IOException {
@@ -116,4 +159,10 @@
         }
         assertEquals("a]]>b", text);
     }
+
+    private static boolean isValidXmlCodePoint(int c) {
+        // http://www.w3.org/TR/REC-xml/#charsets
+        return (c >= 0x20 && c <= 0xd7ff) || (c == 0x9) || (c == 0xa) || (c == 0xd) ||
+                (c >= 0xe000 && c <= 0xfffd) || (c >= 0x10000 && c <= 0x10ffff);
+    }
 }
diff --git a/luni/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTest.java b/luni/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTest.java
index 33ce8fb..8395c00 100644
--- a/luni/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTest.java
+++ b/luni/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTest.java
@@ -126,6 +126,17 @@
                 m2.getDeclaredAnnotations()[0].hashCode());
 
     }
+
+    public static void test35304() throws Exception {
+        Class c = AnnotationTest.class;
+        Class[] parameterTypes = new Class[] { String.class, String.class };
+        Annotation[][] annotations = c.getDeclaredMethod("test35304_method", parameterTypes).getParameterAnnotations();
+        assertEquals(2, annotations.length); // Two parameters.
+        assertEquals(0, annotations[0].length); // No annotations on the first.
+        assertEquals(1, annotations[1].length); // One annotation on the second.
+    }
+
+    private static String test35304_method(String s1, @Deprecated String s2) { return null; }
 }
 
 class AnnotatedClass2 {
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java
index b3b2931..3ea57bf 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java
@@ -33,6 +33,7 @@
 import java.security.InvalidKeyException;
 import java.security.Key;
 import java.security.NoSuchProviderException;
+import java.util.ArrayList;
 import java.util.Arrays;
 
 import javax.crypto.Cipher;
@@ -43,6 +44,8 @@
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
+import libcore.util.SerializationTester;
+
 /**
  */
 public class SealedObjectTest extends TestCase {
@@ -291,4 +294,23 @@
         }
     }
 
+    // http://code.google.com/p/android/issues/detail?id=4834
+    public void testDeserialization() throws Exception {
+        // (Boilerplate so we can create SealedObject instances.)
+        KeyGenerator kg = KeyGenerator.getInstance("DES");
+        Key key = kg.generateKey();
+        Cipher cipher = Cipher.getInstance("DES");
+        cipher.init(Cipher.ENCRYPT_MODE, key);
+
+        // Incorrect use of readUnshared meant you couldn't have two SealedObjects
+        // with the same algorithm or parameters algorithm...
+        ArrayList<SealedObject> sealedObjects = new ArrayList<SealedObject>();
+        for (int i = 0; i < 10; ++i) {
+            sealedObjects.add(new SealedObject("hello", cipher));
+        }
+        String serializedForm = SerializationTester.serializeHex(sealedObjects);
+
+        // ...so this would throw "java.io.InvalidObjectException: Unshared read of back reference".
+        SerializationTester.deserializeHex(serializedForm);
+    }
 }
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherRSATest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherRSATest.java
index d25d958..0e070f6 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherRSATest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherRSATest.java
@@ -15,8 +15,6 @@
  */
 package org.apache.harmony.crypto.tests.javax.crypto.func;
 
-import dalvik.annotation.AndroidOnly;
-
 import junit.framework.TestCase;
 
 public class CipherRSATest extends TestCase {
@@ -55,7 +53,6 @@
         assertEquals(rsa.getFailureMessages(), 0, rsa.getTotalFailuresNumber());
     }
 
-    @AndroidOnly("Fails on RI but succeeds on Android.")
     public void test_RSANoPadding() {
         CipherRSAThread rsa = new CipherRSAThread("RSA", new int[] {1024},
                 new String[] {"ECB"}, new String[] {"NOPADDING"});
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherRSAThread.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherRSAThread.java
index f7445b1..31e1075 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherRSAThread.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherRSAThread.java
@@ -45,6 +45,10 @@
         cip.init(Cipher.DECRYPT_MODE, kp.getPrivate());
         cip.doFinal(output, 0, outputSize, decrypted);
 
-        checkEncodedData(input, decrypted);
+        if ("NOPADDING".equals(getPadding())) {
+            checkPaddedEncodedData(input, decrypted, outputSize - input.length);
+        } else {
+            checkEncodedData(input, decrypted);
+        }
     }
 }
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherThread.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherThread.java
index 4dac176..2fd388b 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherThread.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/CipherThread.java
@@ -57,6 +57,20 @@
         }
     }
 
+    public void checkPaddedEncodedData(byte[] original, byte[] encoded, int offset)
+            throws Exception {
+        for (int i = 0; i < offset; i++) {
+            if (encoded[i] != 0) {
+                throw new Exception("Encoded data is not properly padded at offset " + i);
+            }
+        }
+        for (int i = 0; i < original.length; i++) {
+            if (original[i] != encoded[i + offset]) {
+                throw new Exception("Source and encoded data not match " + getCipherParameters());
+            }
+        }
+    }
+
     public void launcher() {
         Thread thread = null;
 
diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java b/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java
index 3ca11f7..07e3de5 100644
--- a/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java
@@ -19,7 +19,6 @@
 import dalvik.annotation.BrokenTest;
 import junit.framework.TestCase;
 import tests.support.Support_Configuration;
-import tests.support.Support_PortManager;
 import tests.support.Support_TestWebData;
 import tests.support.Support_TestWebServer;
 import tests.support.resource.Support_Resources;
@@ -220,9 +219,8 @@
     public void setUp() throws Exception {
         super.setUp();
 
-        port = Support_PortManager.getNextPort();
         server = new Support_TestWebServer();
-        server.initServer(port, false);
+        port = server.initServer();
         url = new URL("http://localhost:" + port + "/test1");
         uc = url.openConnection();
         url2 =  new URL("http://localhost:" + port + "/test2");
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore2Test.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore2Test.java
index fd27edc..d303903 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore2Test.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore2Test.java
@@ -49,6 +49,7 @@
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Set;
+import libcore.java.security.StandardNames;
 import tests.support.Support_TestProvider;
 
 public class KeyStore2Test extends junit.framework.TestCase {
@@ -817,8 +818,9 @@
 
         try {
             keyTest.setEntry("alias", pke, null);
-            fail();
-        } catch (Exception expected) {
+            assertFalse(StandardNames.IS_RI);  // BKS KeyStore does not require a password
+        } catch (KeyStoreException e) {
+            assertTrue(StandardNames.IS_RI);  // JKS KeyStore requires a password
         }
 
         keyTest.setEntry("alias", pke, pp);
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreSpiTest.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreSpiTest.java
index 4fdddbb..a85459b 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreSpiTest.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreSpiTest.java
@@ -15,21 +15,15 @@
  *  limitations under the License.
  */
 
-/**
- * @author Vera Y. Petrashkova
- * @version $Revision$
- */
-
 package org.apache.harmony.security.tests.java.security;
 
-import junit.framework.TestCase;
-
-import org.apache.harmony.security.tests.support.MyKeyStoreSpi;
-import org.apache.harmony.security.tests.support.MyLoadStoreParams;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.ProtectionParameter;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.KeyStoreSpi;
@@ -39,16 +33,15 @@
 import java.security.SignatureException;
 import java.security.UnrecoverableEntryException;
 import java.security.UnrecoverableKeyException;
-import java.security.KeyStore.LoadStoreParameter;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.util.Date;
+import javax.crypto.SecretKey;
+import junit.framework.TestCase;
+import org.apache.harmony.security.tests.support.MyKeyStoreSpi;
+import org.apache.harmony.security.tests.support.MyLoadStoreParams;
 
-/**
- * Tests for <code>KeyStoreSpi</code> constructor and methods
- *
- */
 public class KeyStoreSpiTest extends TestCase {
 
     @SuppressWarnings("cast")
@@ -86,62 +79,73 @@
         try {
             assertFalse(ksSpi.engineEntryInstanceOf(null,
                     KeyStore.TrustedCertificateEntry.class));
-        } catch (NullPointerException e) {
-            // ok
+        } catch (NullPointerException expected) {
         }
 
         try {
             assertFalse(ksSpi.engineEntryInstanceOf(
                     "test_engineEntryInstanceOf_Alias1", null));
-        } catch (NullPointerException e) {
-            // ok
+        } catch (NullPointerException expected) {
         }
 
 
     }
 
-    public void testKeyStoteSpi01() throws IOException,
+    public void testKeyStoreSpi01() throws IOException,
             NoSuchAlgorithmException, CertificateException,
             UnrecoverableEntryException, KeyStoreException {
-        KeyStoreSpi ksSpi = new MyKeyStoreSpi();
+        final boolean[] keyEntryWasSet = new boolean[1];
+        KeyStoreSpi ksSpi = new MyKeyStoreSpi() {
+            @Override public void engineSetKeyEntry(String alias, Key key, char[] password,
+                Certificate[] chain) throws KeyStoreException { keyEntryWasSet[0] = true; }
+        };
 
-        tmpEntry entry = new tmpEntry();
-        tmpProtection pPar = new tmpProtection();
+        BadKeyStoreEntry badEntry = new BadKeyStoreEntry();
+        BadKeyStoreProtectionParameter badParameter = new BadKeyStoreProtectionParameter();
+
+        KeyStore.SecretKeyEntry dummyEntry = new KeyStore.SecretKeyEntry(new SecretKey() {
+            @Override public String getAlgorithm() { return null; }
+            @Override public String getFormat() { return null; }
+            @Override public byte[] getEncoded() { return null; }
+        });
 
         try {
             ksSpi.engineStore(null);
-        } catch (UnsupportedOperationException e) {
+        } catch (UnsupportedOperationException expected) {
         }
         assertNull("Not null entry", ksSpi.engineGetEntry("aaa", null));
-        assertNull("Not null entry", ksSpi.engineGetEntry(null, pPar));
-        assertNull("Not null entry", ksSpi.engineGetEntry("aaa", pPar));
+        assertNull("Not null entry", ksSpi.engineGetEntry(null, badParameter));
+        assertNull("Not null entry", ksSpi.engineGetEntry("aaa", badParameter));
 
         try {
             ksSpi.engineSetEntry("", null, null);
             fail("KeyStoreException or NullPointerException must be thrown");
-        } catch (KeyStoreException e) {
-        } catch (NullPointerException e) {
+        } catch (KeyStoreException expected) {
+        } catch (NullPointerException expected) {
         }
 
         try {
             ksSpi.engineSetEntry("", new KeyStore.TrustedCertificateEntry(
                     new MyCertificate("type", new byte[0])), null);
             fail("KeyStoreException must be thrown");
-        } catch (KeyStoreException e) {
+        } catch (KeyStoreException expected) {
         }
 
         try {
-            ksSpi.engineSetEntry("aaa", entry, null);
+            ksSpi.engineSetEntry("aaa", badEntry, null);
             fail("KeyStoreException must be thrown");
-        } catch (KeyStoreException e) {
+        } catch (KeyStoreException expected) {
         }
+
+        ksSpi.engineSetEntry("aaa", dummyEntry, null);
+        assertTrue(keyEntryWasSet[0]);
     }
 
     /**
      * Test for <code>KeyStoreSpi()</code> constructor and abstract engine
      * methods. Assertion: creates new KeyStoreSpi object.
      */
-    public void testKeyStoteSpi02() throws NoSuchAlgorithmException,
+    public void testKeyStoreSpi02() throws NoSuchAlgorithmException,
             UnrecoverableKeyException, CertificateException {
         KeyStoreSpi ksSpi = new MyKeyStoreSpi();
         assertNull("engineGetKey(..) must return null", ksSpi.engineGetKey("",
@@ -155,23 +159,23 @@
         try {
             ksSpi.engineSetKeyEntry("", null, new char[0], new Certificate[0]);
             fail("KeyStoreException must be thrown from engineSetKeyEntry(..)");
-        } catch (KeyStoreException e) {
+        } catch (KeyStoreException expected) {
         }
         try {
             ksSpi.engineSetKeyEntry("", new byte[0], new Certificate[0]);
             fail("KeyStoreException must be thrown from engineSetKeyEntry(..)");
-        } catch (KeyStoreException e) {
+        } catch (KeyStoreException expected) {
         }
         try {
             ksSpi.engineSetCertificateEntry("", null);
             fail("KeyStoreException must be thrown "
                     + "from engineSetCertificateEntry(..)");
-        } catch (KeyStoreException e) {
+        } catch (KeyStoreException expected) {
         }
         try {
             ksSpi.engineDeleteEntry("");
             fail("KeyStoreException must be thrown from engineDeleteEntry(..)");
-        } catch (KeyStoreException e) {
+        } catch (KeyStoreException expected) {
         }
         assertNull("engineAliases() must return null", ksSpi.engineAliases());
         assertFalse("engineContainsAlias(..) must return false", ksSpi
@@ -180,7 +184,7 @@
         try {
             ksSpi.engineStore(null, null);
             fail("IOException must be thrown");
-        } catch (IOException e) {
+        } catch (IOException expected) {
         }
     }
 
@@ -202,35 +206,30 @@
         try {
             ksSpi.engineLoad(null);
             fail("Should throw exception");
-        } catch (RuntimeException e) {
-            assertSame(msg, e.getMessage());
+        } catch (RuntimeException expected) {
+            assertSame(msg, expected.getMessage());
         }
 
         // test: protection parameter is null
         try {
             ksSpi.engineLoad(new MyLoadStoreParams(null));
             fail("No expected UnsupportedOperationException");
-        } catch (UnsupportedOperationException e) {
+        } catch (UnsupportedOperationException expected) {
         }
 
         // test: protection parameter is not instanceof
         // PasswordProtection or CallbackHandlerProtection
         try {
-            ksSpi.engineLoad(new MyLoadStoreParams(new tmpProtection()));
+            ksSpi.engineLoad(new MyLoadStoreParams(new BadKeyStoreProtectionParameter()));
             fail("No expected UnsupportedOperationException");
-        } catch (UnsupportedOperationException e) {
+        } catch (UnsupportedOperationException expected) {
         }
     }
 }
 
-/**
- * Additional class implements KeyStore.Entry interface
- */
-class tmpEntry implements KeyStore.Entry {
-}
-
-class tmpProtection implements KeyStore.ProtectionParameter {
-}
+// These are "Bad" because they are not expected inner subclasses of the KeyStore class.
+class BadKeyStoreEntry implements Entry {}
+class BadKeyStoreProtectionParameter implements ProtectionParameter {}
 
 @SuppressWarnings("unused")
 class MyCertificate extends Certificate {
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/SecureRandom2Test.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/SecureRandom2Test.java
index cf030c7..aa0ec67 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/SecureRandom2Test.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/SecureRandom2Test.java
@@ -301,40 +301,15 @@
      * as it tends to be error prone and open up security holes.
      * See {@link SecureRandom} for more details about insecure seeding.
      *
-     * @see #testSameSeedGeneratesSameResultsWhenConstructorIsUsed()
+     * Note that this only works with the Harmony "Crypto" provider.
      */
     public void testSameSeedGeneratesSameResults() throws Exception {
         byte[] seed1 = { 'a', 'b', 'c' };
-        SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG");
+        SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG", "Crypto");
         sr1.setSeed(seed1);
 
         byte[] seed2 = { 'a', 'b', 'c' };
-        SecureRandom sr2 = SecureRandom.getInstance("SHA1PRNG");
-        sr2.setSeed(seed2);
-
-        assertTrue(sr1.nextLong() == sr2.nextLong());
-    }
-
-    /**
-     * Same tests as {@link #testSameSeedGeneratesSameResults()}, except
-     * here we use the constructor, not {@link SecureRandom#getInstance(String)}.
-     *
-     * Note that Android behaves differently than the reference implementation.
-     * This test fails on the reference implementation.
-     *
-     * In the future, it may make sense to change our implementation to
-     * match the reference implementation.  It may also make sense to
-     * disallow seeding {@code SecureRandom} completely, as it tends to
-     * be error prone and open up security holes.  See {@link SecureRandom}
-     * for more details about insecure seeding.
-     */
-    public void testSameSeedGeneratesSameResultsWhenConstructorIsUsed() {
-        byte[] seed1 = { 'a', 'b', 'c' };
-        SecureRandom sr1 = new SecureRandom();
-        sr1.setSeed(seed1);
-
-        byte[] seed2 = { 'a', 'b', 'c' };
-        SecureRandom sr2 = new SecureRandom();
+        SecureRandom sr2 = SecureRandom.getInstance("SHA1PRNG", "Crypto");
         sr2.setSeed(seed2);
 
         assertTrue(sr1.nextLong() == sr2.nextLong());
@@ -348,10 +323,12 @@
      * SHA1PRNG, so users of {@code SecureRandom} should not assume
      * the same seed will always produce the same value.  This test
      * is not a guarantee of future compatibility.
+     *
+     * In fact, this test only works with the Harmony "Crypto" provider.
      */
     public void testAlwaysSameValueWithSameSeed() throws Exception {
         byte[] seed1 = { 'a', 'b', 'c' };
-        SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG");
+        SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG", "Crypto");
         sr1.setSeed(seed1);
 
         // This long value has no special meaning and may change in the future.
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
index 2d78238..15b175c 100644
--- a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
@@ -577,7 +577,7 @@
         ExecutorService executor = Executors.newSingleThreadExecutor();
         Future<TestSSLHandshakeCallbacks> future = executor.submit(
                 new Callable<TestSSLHandshakeCallbacks>() {
-            public TestSSLHandshakeCallbacks call() throws Exception {
+            @Override public TestSSLHandshakeCallbacks call() throws Exception {
                 Socket socket = (client
                                  ? new Socket(listener.getInetAddress(),
                                               listener.getLocalPort())
@@ -1658,6 +1658,12 @@
                 assertNotNull(b);
                 int session2 = NativeCrypto.d2i_SSL_SESSION(b);
                 assertTrue(session2 != NULL);
+
+                // Make sure d2i_SSL_SESSION retores SSL_SESSION_cipher value http://b/7091840
+                assertTrue(NativeCrypto.SSL_SESSION_cipher(session2) != null);
+                assertEquals(NativeCrypto.SSL_SESSION_cipher(session),
+                             NativeCrypto.SSL_SESSION_cipher(session2));
+
                 NativeCrypto.SSL_SESSION_free(session2);
                 super.afterHandshake(session, s, c, sock, fd, callback);
             }
@@ -1679,7 +1685,7 @@
         assertEquals(NULL, NativeCrypto.d2i_SSL_SESSION(new byte[0]));
         assertEquals(NULL, NativeCrypto.d2i_SSL_SESSION(new byte[1]));
 
-        // positively testing by test_i2d_SSL_SESSION
+        // positive testing by test_i2d_SSL_SESSION
     }
 
     public void test_X509_NAME_hashes() {
@@ -1701,4 +1707,25 @@
             // Success
         }
     }
+
+    public void test_RAND_bytes_Success() throws Exception {
+        byte[] output = new byte[32];
+        NativeCrypto.RAND_bytes(output);
+
+        boolean isZero = true;
+        for (int i = 0; i < output.length; i++) {
+            isZero &= (output[i] == 0);
+        }
+
+        assertFalse("Random output was zero. This is a very low probability event "
+                + "and probably indicates an error.", isZero);
+    }
+
+    public void test_RAND_bytes_Null_Failure() throws Exception {
+        byte[] output = null;
+        try {
+            NativeCrypto.RAND_bytes(output);
+            fail("Should be an error on null buffer input");
+        } catch (RuntimeException success) { }
+    }
 }
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStoreTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStoreTest.java
index 6d0f50c..52880df 100644
--- a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStoreTest.java
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStoreTest.java
@@ -22,11 +22,13 @@
 import java.security.KeyStore;
 import java.security.PrivateKey;
 import java.security.PublicKey;
+import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
+import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import javax.security.auth.x500.X500Principal;
@@ -411,6 +413,15 @@
         assertAliases(alias1, alias2);
         assertEquals(getChain()[2], store.findIssuer(getChain()[1]));
         assertEquals(getChain()[1], store.findIssuer(getChain()[0]));
+
+        X509Certificate[] expected = getChain();
+        List<X509Certificate> actualList = store.getCertificateChain(expected[0]);
+
+        assertEquals("Generated CA list should be same length", expected.length, actualList.size());
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("Chain value should be the same for position " + i, expected[i],
+                    actualList.get(i));
+        }
         resetStore();
     }
 
diff --git a/luni/src/test/java/tests/api/java/util/SimpleTimeZoneTest.java b/luni/src/test/java/tests/api/java/util/SimpleTimeZoneTest.java
index e27ec0d..618cbe4 100644
--- a/luni/src/test/java/tests/api/java/util/SimpleTimeZoneTest.java
+++ b/luni/src/test/java/tests/api/java/util/SimpleTimeZoneTest.java
@@ -691,6 +691,7 @@
      * java.util.SimpleTimeZone#setStartRule(int, int, int, int, boolean)
      */
     public void test_setStartRuleIIIIZ() {
+        TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
         // Test for method void java.util.SimpleTimeZone.setStartRule(int, int,
         // int, int, boolean)
         SimpleTimeZone st = new SimpleTimeZone(TimeZone.getTimeZone("EST").getRawOffset(), "EST");
diff --git a/luni/src/test/java/tests/api/javax/net/ServerSocketFactoryTest.java b/luni/src/test/java/tests/api/javax/net/ServerSocketFactoryTest.java
index 053200f..34d7aed 100644
--- a/luni/src/test/java/tests/api/javax/net/ServerSocketFactoryTest.java
+++ b/luni/src/test/java/tests/api/javax/net/ServerSocketFactoryTest.java
@@ -30,158 +30,77 @@
 
 import junit.framework.TestCase;
 
-import tests.support.Support_PortManager;
-
-
-/**
- * Tests for <code>ServerSocketFactory</code> class constructors and methods.
- */
 public class ServerSocketFactoryTest extends TestCase {
 
-    /**
-     * javax.net.SocketFactory#SocketFactory()
-     */
     public void test_Constructor() {
-        try {
-            ServerSocketFactory sf = new MyServerSocketFactory();
-        } catch (Exception e) {
-            fail("Unexpected exception " + e.toString());
-        }
+        ServerSocketFactory sf = new MyServerSocketFactory();
     }
 
-    /**
-     * javax.net.ServerSocketFactory#createServerSocket()
-     */
-    public final void test_createServerSocket_01() {
+    public final void test_createServerSocket() throws Exception {
         ServerSocketFactory sf = ServerSocketFactory.getDefault();
-        try {
-            ServerSocket ss = sf.createServerSocket();
-            assertNotNull(ss);
-        } catch (SocketException e) {
-        } catch (Exception e) {
-            fail(e.toString());
-        }
+        ServerSocket ss = sf.createServerSocket();
+        assertNotNull(ss);
+        ss.close();
     }
 
-    /**
-     * javax.net.ServerSocketFactory#createServerSocket(int port)
-     */
-    public final void test_createServerSocket_02() {
+    public final void test_createServerSocket_I() throws Exception {
         ServerSocketFactory sf = ServerSocketFactory.getDefault();
-        int portNumber = Support_PortManager.getNextPort();
+        ServerSocket ss = sf.createServerSocket(0);
+        assertNotNull(ss);
 
         try {
-            ServerSocket ss = sf.createServerSocket(portNumber);
-            assertNotNull(ss);
-        } catch (Exception ex) {
-            fail("Unexpected exception: " + ex);
-        }
-
-        try {
-            sf.createServerSocket(portNumber);
+            sf.createServerSocket(ss.getLocalPort());
             fail("IOException wasn't thrown");
-        } catch (IOException ioe) {
-            //expected
-        } catch (Exception ex) {
-            fail(ex + " was thrown instead of IOException");
+        } catch (IOException expected) {
         }
 
+        ss.close();
+
         try {
             sf.createServerSocket(-1);
             fail("IllegalArgumentException wasn't thrown");
-        } catch (IllegalArgumentException ioe) {
-            //expected
-        } catch (Exception ex) {
-            fail(ex + " was thrown instead of IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
         }
     }
 
-    /**
-     * javax.net.ServerSocketFactory#createServerSocket(int port, int backlog)
-     */
-    public final void test_createServerSocket_03() {
+    public final void test_createServerSocket_II() throws Exception {
         ServerSocketFactory sf = ServerSocketFactory.getDefault();
-        int portNumber = Support_PortManager.getNextPort();
+        ServerSocket ss = sf.createServerSocket(0, 0);
+        assertNotNull(ss);
 
         try {
-            ServerSocket ss = sf.createServerSocket(portNumber, 0);
-            assertNotNull(ss);
-        } catch (Exception ex) {
-            fail("Unexpected exception: " + ex);
-        }
-
-        try {
-            sf.createServerSocket(portNumber, 0);
+            sf.createServerSocket(ss.getLocalPort(), 0);
             fail("IOException wasn't thrown");
-        } catch (IOException ioe) {
-            //expected
-        } catch (Exception ex) {
-            fail(ex + " was thrown instead of IOException");
+        } catch (IOException expected) {
         }
 
+        ss.close();
+
         try {
             sf.createServerSocket(65536, 0);
             fail("IllegalArgumentException wasn't thrown");
-        } catch (IllegalArgumentException ioe) {
-            //expected
-        } catch (Exception ex) {
-            fail(ex + " was thrown instead of IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
         }
     }
 
-    /**
-     * javax.net.ServerSocketFactory#createServerSocket(int port, int backlog, InetAddress ifAddress)
-     */
-    public final void test_createServerSocket_04() {
+    public final void test_createServerSocket_IIInetAddress() throws Exception {
         ServerSocketFactory sf = ServerSocketFactory.getDefault();
-        int portNumber = Support_PortManager.getNextPort();
+
+        ServerSocket ss = sf.createServerSocket(0, 0, InetAddress.getLocalHost());
+        assertNotNull(ss);
 
         try {
-            ServerSocket ss = sf.createServerSocket(portNumber, 0, InetAddress.getLocalHost());
-            assertNotNull(ss);
-        } catch (Exception ex) {
-            fail("Unexpected exception: " + ex);
-        }
-
-        try {
-            sf.createServerSocket(portNumber, 0, InetAddress.getLocalHost());
+            sf.createServerSocket(ss.getLocalPort(), 0, InetAddress.getLocalHost());
             fail("IOException wasn't thrown");
-        } catch (IOException ioe) {
-            //expected
-        } catch (Exception ex) {
-            fail(ex + " was thrown instead of IOException");
+        } catch (IOException expected) {
         }
 
+        ss.close();
+
         try {
             sf.createServerSocket(Integer.MAX_VALUE, 0, InetAddress.getLocalHost());
             fail("IllegalArgumentException wasn't thrown");
-        } catch (IllegalArgumentException ioe) {
-            //expected
-        } catch (Exception ex) {
-            fail(ex + " was thrown instead of IllegalArgumentException");
-        }
-    }
-
-    /**
-     * javax.net.ServerSocketFactory#getDefault()
-     */
-    public final void test_getDefault() {
-        ServerSocketFactory sf = ServerSocketFactory.getDefault();
-        ServerSocket s;
-        try {
-            s = sf.createServerSocket(0);
-            s.close();
-        } catch (IOException e) {
-        }
-        try {
-            s = sf.createServerSocket(0, 50);
-            s.close();
-        } catch (IOException e) {
-        }
-        try {
-            s = sf.createServerSocket(0, 50, InetAddress.getLocalHost());
-            s.close();
-        } catch (IOException e) {
+        } catch (IllegalArgumentException expected) {
         }
     }
 }
diff --git a/luni/src/test/java/tests/api/javax/net/SocketFactoryTest.java b/luni/src/test/java/tests/api/javax/net/SocketFactoryTest.java
index 2250602..e939a9b 100644
--- a/luni/src/test/java/tests/api/javax/net/SocketFactoryTest.java
+++ b/luni/src/test/java/tests/api/javax/net/SocketFactoryTest.java
@@ -33,200 +33,135 @@
 
 import junit.framework.TestCase;
 
-import tests.support.Support_PortManager;
-
-
-/**
- * Tests for <code>SocketFactory</code> class methods.
- */
 public class SocketFactoryTest extends TestCase {
 
-    /**
-     * javax.net.SocketFactory#SocketFactory()
-     */
-    public void test_Constructor() {
-        try {
-            MySocketFactory sf = new MySocketFactory();
-        } catch (Exception e) {
-            fail("Unexpected exception " + e.toString());
-        }
+    public void test_Constructor() throws Exception {
+        new MySocketFactory();
     }
 
-    /**
-     * javax.net.SocketFactory#createSocket()
-     */
-    public final void test_createSocket_01() {
+    public final void test_createSocket() throws Exception {
         SocketFactory sf = SocketFactory.getDefault();
 
-        try {
-            Socket s = sf.createSocket();
-            assertNotNull(s);
-            assertEquals(-1, s.getLocalPort());
-            assertEquals(0, s.getPort());
-        } catch (Exception e) {
-            fail("Unexpected exception: " + e);
-        }
+        Socket s = sf.createSocket();
+        assertNotNull(s);
+        assertEquals(-1, s.getLocalPort());
+        assertEquals(0, s.getPort());
 
         MySocketFactory msf = new MySocketFactory();
         try {
             msf.createSocket();
             fail("No expected SocketException");
-        } catch (SocketException e) {
-        } catch (IOException e) {
-            fail(e.toString());
+        } catch (SocketException expected) {
         }
     }
 
-    /**
-     * javax.net.SocketFactory#createSocket(String host, int port)
-     */
-    public final void test_createSocket_02() {
+    public final void test_createSocket_StringI() throws Exception {
         SocketFactory sf = SocketFactory.getDefault();
-        int portNumber = Support_PortManager.getNextPort();
-        int sport = startServer("Cons String,I");
+        int sport = new ServerSocket(0).getLocalPort();
         int[] invalidPorts = {Integer.MIN_VALUE, -1, 65536, Integer.MAX_VALUE};
 
-        try {
-            Socket s = sf.createSocket(InetAddress.getLocalHost().getHostName(), sport);
-            assertNotNull(s);
-            assertTrue("Failed to create socket", s.getPort() == sport);
-        } catch (Exception e) {
-            fail("Unexpected exception: " + e);
-        }
+        Socket s = sf.createSocket(InetAddress.getLocalHost().getHostName(), sport);
+        assertNotNull(s);
+        assertTrue("Failed to create socket", s.getPort() == sport);
 
         try {
-            Socket s = sf.createSocket("bla-bla", sport);
+            sf.createSocket("bla-bla", sport);
             fail("UnknownHostException wasn't thrown");
-        } catch (UnknownHostException uhe) {
-            //expected
-        } catch (Exception e) {
-            fail(e + " was thrown instead of UnknownHostException");
+        } catch (UnknownHostException expected) {
         }
 
         for (int i = 0; i < invalidPorts.length; i++) {
             try {
-                Socket s = sf.createSocket(InetAddress.getLocalHost().getHostName(), invalidPorts[i]);
+                sf.createSocket(InetAddress.getLocalHost().getHostName(), invalidPorts[i]);
                 fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
-            } catch (IllegalArgumentException iae) {
-                //expected
-            } catch (Exception e) {
-                fail(e + " was thrown instead of IllegalArgumentException for " + invalidPorts[i]);
+            } catch (IllegalArgumentException expected) {
             }
         }
 
         try {
-            Socket s = sf.createSocket(InetAddress.getLocalHost().getHostName(), portNumber);
+            sf.createSocket(InetAddress.getLocalHost().getHostName(), s.getLocalPort());
             fail("IOException wasn't thrown");
-        } catch (IOException ioe) {
-            //expected
+        } catch (IOException expected) {
         }
 
         SocketFactory f = SocketFactory.getDefault();
         try {
-            Socket s = f.createSocket("localhost", 8082);
+            f.createSocket(InetAddress.getLocalHost().getHostName(), 8082);
             fail("IOException wasn't thrown ...");
-        } catch (IOException e) {
+        } catch (IOException expected) {
         }
     }
 
-    /**
-     * javax.net.SocketFactory#createSocket(InetAddress host, int port)
-     */
-    public final void test_createSocket_03() {
+    public final void test_createSocket_InetAddressI() throws Exception {
         SocketFactory sf = SocketFactory.getDefault();
-        int portNumber = Support_PortManager.getNextPort();
-        int sport = startServer("Cons InetAddress,I");
+        int sport = new ServerSocket(0).getLocalPort();
         int[] invalidPorts = {Integer.MIN_VALUE, -1, 65536, Integer.MAX_VALUE};
 
-        try {
-            Socket s = sf.createSocket(InetAddress.getLocalHost(), sport);
-            assertNotNull(s);
-            assertTrue("Failed to create socket", s.getPort() == sport);
-        } catch (Exception e) {
-            fail("Unexpected exception: " + e);
-        }
+        Socket s = sf.createSocket(InetAddress.getLocalHost(), sport);
+        assertNotNull(s);
+        assertTrue("Failed to create socket", s.getPort() == sport);
 
         for (int i = 0; i < invalidPorts.length; i++) {
             try {
-                Socket s = sf.createSocket(InetAddress.getLocalHost(), invalidPorts[i]);
+                sf.createSocket(InetAddress.getLocalHost(), invalidPorts[i]);
                 fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
-            } catch (IllegalArgumentException iae) {
-                //expected
-            } catch (Exception e) {
-                fail(e + " was thrown instead of IllegalArgumentException for " + invalidPorts[i]);
+            } catch (IllegalArgumentException expected) {
             }
         }
 
         try {
-            Socket s = sf.createSocket(InetAddress.getLocalHost(), portNumber);
+            sf.createSocket(InetAddress.getLocalHost(), s.getLocalPort());
             fail("IOException wasn't thrown");
-        } catch (IOException ioe) {
-            //expected
+        } catch (IOException expected) {
         }
 
         SocketFactory f = SocketFactory.getDefault();
         try {
-            Socket s = f.createSocket(InetAddress.getLocalHost(), 8081);
+            f.createSocket(InetAddress.getLocalHost(), 8081);
             fail("IOException wasn't thrown ...");
-        } catch (IOException e) {
+        } catch (IOException expected) {
         }
     }
 
-    /**
-     * javax.net.SocketFactory#createSocket(InetAddress address, int port,
-     *                                             InetAddress localAddress, int localPort)
-     */
-    public final void test_createSocket_04() {
+    public final void test_createSocket_InetAddressIInetAddressI() throws Exception {
         SocketFactory sf = SocketFactory.getDefault();
-        int portNumber = Support_PortManager.getNextPort();
-        int sport = startServer("Cons InetAddress,I,InetAddress,I");
+        int sport = new ServerSocket(0).getLocalPort();
         int[] invalidPorts = {Integer.MIN_VALUE, -1, 65536, Integer.MAX_VALUE};
 
-        try {
-            Socket s = sf.createSocket(InetAddress.getLocalHost(), sport,
-                                       InetAddress.getLocalHost(), portNumber);
-            assertNotNull(s);
-            assertTrue("1: Failed to create socket", s.getPort() == sport);
-            assertTrue("2: Failed to create socket", s.getLocalPort() == portNumber);
-        } catch (Exception e) {
-            fail("Unexpected exception: " + e);
-        }
+        Socket s = sf.createSocket(InetAddress.getLocalHost(), sport,
+                                   InetAddress.getLocalHost(), 0);
+        assertNotNull(s);
+        assertTrue("1: Failed to create socket", s.getPort() == sport);
+        int portNumber = s.getLocalPort();
 
         for (int i = 0; i < invalidPorts.length; i++) {
             try {
-                Socket s = sf.createSocket(InetAddress.getLocalHost(), invalidPorts[i],
-                                           InetAddress.getLocalHost(), portNumber);
+              sf.createSocket(InetAddress.getLocalHost(), invalidPorts[i],
+                              InetAddress.getLocalHost(), portNumber);
                 fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
-            } catch (IllegalArgumentException iae) {
-                //expected
-            } catch (Exception e) {
-                fail(e + " was thrown instead of IllegalArgumentException for " + invalidPorts[i]);
+            } catch (IllegalArgumentException expected) {
             }
 
             try {
-                Socket s = sf.createSocket(InetAddress.getLocalHost(), sport,
-                                           InetAddress.getLocalHost(), invalidPorts[i]);
+                sf.createSocket(InetAddress.getLocalHost(), sport,
+                                InetAddress.getLocalHost(), invalidPorts[i]);
                 fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
-            } catch (IllegalArgumentException iae) {
-                //expected
-            } catch (Exception e) {
-                fail(e + " was thrown instead of IllegalArgumentException for " + invalidPorts[i]);
+            } catch (IllegalArgumentException expected) {
             }
         }
 
         try {
-            Socket s = sf.createSocket(InetAddress.getLocalHost(), sport,
-                                       InetAddress.getLocalHost(), portNumber);
+            sf.createSocket(InetAddress.getLocalHost(), sport,
+                            InetAddress.getLocalHost(), portNumber);
             fail("IOException wasn't thrown");
-        } catch (IOException ioe) {
-            //expected
+        } catch (IOException expected) {
         }
 
         SocketFactory f = SocketFactory.getDefault();
         try {
-            Socket s = f.createSocket(InetAddress.getLocalHost(), 8081, InetAddress.getLocalHost(), 8082);
+            f.createSocket(InetAddress.getLocalHost(), 8081, InetAddress.getLocalHost(), 8082);
             fail("IOException wasn't thrown ...");
-        } catch (IOException e) {
+        } catch (IOException expected) {
         }
     }
 
@@ -234,59 +169,41 @@
      * javax.net.SocketFactory#createSocket(String host, int port,
      *                                             InetAddress localHost, int localPort)
      */
-    public final void test_createSocket_05() {
+    public final void test_createSocket_05() throws Exception {
         SocketFactory sf = SocketFactory.getDefault();
-        int portNumber = Support_PortManager.getNextPort();
-        int sport = startServer("Cons String,I,InetAddress,I");
+        int sport = new ServerSocket(0).getLocalPort();
         int[] invalidPorts = {Integer.MIN_VALUE, -1, 65536, Integer.MAX_VALUE};
 
-        try {
-            Socket s = sf.createSocket(InetAddress.getLocalHost().getHostName(), sport,
-                                       InetAddress.getLocalHost(), portNumber);
-            assertNotNull(s);
-            assertTrue("1: Failed to create socket", s.getPort() == sport);
-            assertTrue("2: Failed to create socket", s.getLocalPort() == portNumber);
-        } catch (Exception e) {
-            fail("Unexpected exception: " + e);
-        }
+        Socket s = sf.createSocket(InetAddress.getLocalHost().getHostName(), sport,
+                                   InetAddress.getLocalHost(), 0);
+        assertNotNull(s);
+        assertTrue("1: Failed to create socket", s.getPort() == sport);
 
-        portNumber = Support_PortManager.getNextPort();
         try {
-            Socket s = sf.createSocket("bla-bla", sport, InetAddress.getLocalHost(), portNumber);
+            sf.createSocket("bla-bla", sport, InetAddress.getLocalHost(), 0);
             fail("UnknownHostException wasn't thrown");
-        } catch (UnknownHostException uhe) {
-            //expected
-        } catch (Exception e) {
-            fail(e + " was thrown instead of UnknownHostException");
+        } catch (UnknownHostException expected) {
         }
 
         for (int i = 0; i < invalidPorts.length; i++) {
-            portNumber = Support_PortManager.getNextPort();
             try {
-                Socket s = sf.createSocket(InetAddress.getLocalHost().getHostName(), invalidPorts[i],
-                                           InetAddress.getLocalHost(), portNumber);
+                sf.createSocket(InetAddress.getLocalHost().getHostName(), invalidPorts[i],
+                                InetAddress.getLocalHost(), 0);
                 fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
-            } catch (IllegalArgumentException iae) {
-                //expected
-            } catch (Exception e) {
-                fail(e + " was thrown instead of IllegalArgumentException for " + invalidPorts[i]);
+            } catch (IllegalArgumentException expected) {
             }
             try {
-                Socket s = sf.createSocket(InetAddress.getLocalHost().getHostName(), sport,
-                                           InetAddress.getLocalHost(), invalidPorts[i]);
+                sf.createSocket(InetAddress.getLocalHost().getHostName(), sport,
+                                InetAddress.getLocalHost(), invalidPorts[i]);
                 fail("IllegalArgumentException wasn't thrown for " + invalidPorts[i]);
-            } catch (IllegalArgumentException iae) {
-                //expected
-            } catch (Exception e) {
-                fail(e + " was thrown instead of IllegalArgumentException for " + invalidPorts[i]);
+            } catch (IllegalArgumentException expected) {
             }
         }
 
-        SocketFactory f = SocketFactory.getDefault();
         try {
-            Socket s = f.createSocket("localhost", 8081, InetAddress.getLocalHost(), 8082);
+            sf.createSocket(InetAddress.getLocalHost().getHostName(), 8081, InetAddress.getLocalHost(), 8082);
             fail("IOException wasn't thrown ...");
-        } catch (IOException e) {
+        } catch (IOException expected) {
         }
     }
 
@@ -297,12 +214,12 @@
         SocketFactory sf = SocketFactory.getDefault();
         Socket s;
         try {
-            s = sf.createSocket("localhost", 8082);
+            s = sf.createSocket(InetAddress.getLocalHost().getHostName(), 8082);
             s.close();
         } catch (IOException e) {
         }
         try {
-            s = sf.createSocket("localhost", 8081, InetAddress.getLocalHost(), 8082);
+            s = sf.createSocket(InetAddress.getLocalHost().getHostName(), 8081, InetAddress.getLocalHost(), 8082);
             s.close();
         } catch (IOException e) {
         }
@@ -317,17 +234,6 @@
         } catch (IOException e) {
         }
     }
-
-    protected int startServer(String name) {
-        int portNumber = Support_PortManager.getNextPort();
-        ServerSocket ss = null;
-        try {
-            ss = new ServerSocket(portNumber);
-        } catch (IOException e) {
-            fail(name + ": " + e);
-        }
-        return ss.getLocalPort();
-    }
 }
 
 class MySocketFactory extends SocketFactory {
diff --git a/luni/src/test/java/tests/api/javax/net/ssl/HandshakeCompletedEventTest.java b/luni/src/test/java/tests/api/javax/net/ssl/HandshakeCompletedEventTest.java
index 8a02f9c..c075cea 100644
--- a/luni/src/test/java/tests/api/javax/net/ssl/HandshakeCompletedEventTest.java
+++ b/luni/src/test/java/tests/api/javax/net/ssl/HandshakeCompletedEventTest.java
@@ -42,7 +42,6 @@
 import junit.framework.TestCase;
 import libcore.io.Base64;
 import org.apache.harmony.xnet.tests.support.mySSLSession;
-import tests.support.Support_PortManager;
 
 /**
  * Tests for <code>HandshakeCompletedEvent</code> class constructors and methods.
@@ -50,7 +49,7 @@
  */
 public class HandshakeCompletedEventTest extends TestCase {
 
-    String certificate = "-----BEGIN CERTIFICATE-----\n"
+    private String certificate = "-----BEGIN CERTIFICATE-----\n"
         + "MIICZTCCAdICBQL3AAC2MA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMSAw\n"
         + "HgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjEuMCwGA1UECxMlU2VjdXJl\n"
         + "IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NzAyMjAwMDAwMDBa\n"
@@ -200,11 +199,10 @@
     // TrustManager
 
 
-    SSLSocket socket;
-    SSLSocket serverSocket;
-    MyHandshakeListener listener;
-    int port = Support_PortManager.getNextPort();
-    String host = "localhost";
+    private SSLSocket socket;
+    private SSLServerSocket serverSocket;
+    private MyHandshakeListener listener;
+    private String host = "localhost";
 
     private String PASSWORD = "android";
 
@@ -398,35 +396,34 @@
 
         private boolean provideKeys;
 
-        public TestServer(boolean provideKeys, int clientAuth, String keys) {
+        public TestServer(boolean provideKeys, int clientAuth, String keys) throws Exception {
             this.keys = keys;
             this.clientAuth = clientAuth;
             this.provideKeys = provideKeys;
 
             trustManager = new TestTrustManager();
+
+            KeyManager[] keyManagers = provideKeys ? getKeyManagers(keys) : null;
+            TrustManager[] trustManagers = new TrustManager[] { trustManager };
+
+            SSLContext sslContext = SSLContext.getInstance("TLS");
+            sslContext.init(keyManagers, trustManagers, null);
+
+            serverSocket = (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket();
+
+            if (clientAuth == CLIENT_AUTH_WANTED) {
+                serverSocket.setWantClientAuth(true);
+            } else if (clientAuth == CLIENT_AUTH_NEEDED) {
+                serverSocket.setNeedClientAuth(true);
+            } else {
+                serverSocket.setWantClientAuth(false);
+            }
+
+            serverSocket.bind(new InetSocketAddress(0));
         }
 
         public void run() {
             try {
-                KeyManager[] keyManagers = provideKeys ? getKeyManagers(keys) : null;
-                TrustManager[] trustManagers = new TrustManager[] { trustManager };
-
-                SSLContext sslContext = SSLContext.getInstance("TLS");
-                sslContext.init(keyManagers, trustManagers, null);
-
-                SSLServerSocket serverSocket = (SSLServerSocket)
-                        sslContext.getServerSocketFactory().createServerSocket();
-
-                if (clientAuth == CLIENT_AUTH_WANTED) {
-                    serverSocket.setWantClientAuth(true);
-                } else if (clientAuth == CLIENT_AUTH_NEEDED) {
-                    serverSocket.setNeedClientAuth(true);
-                } else {
-                    serverSocket.setWantClientAuth(false);
-                }
-
-                serverSocket.bind(new InetSocketAddress(port));
-
                 SSLSocket clientSocket = (SSLSocket)serverSocket.accept();
 
                 InputStream istream = clientSocket.getInputStream();
@@ -497,7 +494,7 @@
 
                 SSLSocket socket = (SSLSocket)sslContext.getSocketFactory().createSocket();
 
-                socket.connect(new InetSocketAddress(port));
+                socket.connect(serverSocket.getLocalSocketAddress());
                 socket.addHandshakeCompletedListener(listener);
                 socket.startHandshake();
 
diff --git a/luni/src/test/java/tests/api/javax/net/ssl/SSLServerSocketTest.java b/luni/src/test/java/tests/api/javax/net/ssl/SSLServerSocketTest.java
index cc96782..5086f65 100644
--- a/luni/src/test/java/tests/api/javax/net/ssl/SSLServerSocketTest.java
+++ b/luni/src/test/java/tests/api/javax/net/ssl/SSLServerSocketTest.java
@@ -20,8 +20,6 @@
 
 import libcore.io.Base64;
 
-import tests.support.Support_PortManager;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -120,127 +118,78 @@
     /**
      * javax.net.ssl.SSLServerSocket#SSLServerSocket()
      */
-    public void testConstructor_01() {
-        try {
-            SSLServerSocket ssl = new mySSLServerSocket();
-        } catch (Exception ex) {
-            fail("Unexpected exception was thrown " + ex);
-        }
+    public void testConstructor() throws Exception {
+        SSLServerSocket ssl = new mySSLServerSocket();
     }
 
     /**
      * javax.net.ssl.SSLServerSocket#SSLServerSocket(int port)
      */
-    public void testConstructor_02() {
-        SSLServerSocket ssl;
-        int portNumber = Support_PortManager.getNextPort();
+    public void testConstructor_I() throws Exception {
         int[] port_invalid = {-1, 65536, Integer.MIN_VALUE, Integer.MAX_VALUE};
 
-        try {
-            ssl = new mySSLServerSocket(portNumber);
-            assertEquals(portNumber, ssl.getLocalPort());
-        } catch (Exception ex) {
-            fail("Unexpected exception was thrown " + ex);
-        }
+        SSLServerSocket ssl = new mySSLServerSocket(0);
 
         for (int i = 0; i < port_invalid.length; i++) {
             try {
-                ssl = new mySSLServerSocket(port_invalid[i]);
+                new mySSLServerSocket(port_invalid[i]);
                 fail("IllegalArgumentException should be thrown");
-            } catch (IllegalArgumentException iae) {
-                //expected
-            } catch (Exception e) {
-                fail(e + " was thrown instead of IllegalArgumentException");
+            } catch (IllegalArgumentException expected) {
             }
         }
 
         try {
-            ssl = new mySSLServerSocket(portNumber);
-            new mySSLServerSocket(portNumber);
+            new mySSLServerSocket(ssl.getLocalPort());
             fail("IOException Expected when opening an already opened port");
-        } catch (IOException ioe) {
-            // expected
-        } catch (Exception ex) {
-            fail("Unexpected exception was thrown " + ex);
+        } catch (IOException expected) {
         }
     }
 
     /**
      * javax.net.ssl.SSLServerSocket#SSLServerSocket(int port, int backlog)
      */
-    public void testConstructor_03() {
-        mySSLServerSocket ssl;
-        int portNumber = Support_PortManager.getNextPort();
+    public void testConstructor_II() throws Exception {
+        mySSLServerSocket ssl = new mySSLServerSocket(0, 1);
         int[] port_invalid = {-1, Integer.MIN_VALUE, Integer.MAX_VALUE};
 
-        try {
-            ssl = new mySSLServerSocket(portNumber, 1);
-            assertEquals(portNumber, ssl.getLocalPort());
-        } catch (Exception ex) {
-            fail("Unexpected exception was thrown");
-        }
-
         for (int i = 0; i < port_invalid.length; i++) {
             try {
-                ssl = new mySSLServerSocket(port_invalid[i], 1);
+                new mySSLServerSocket(port_invalid[i], 1);
                 fail("IllegalArgumentException should be thrown");
-            } catch (IllegalArgumentException iae) {
-                // expected
-            } catch (Exception e) {
-                fail(e + " was thrown instead of IllegalArgumentException");
+            } catch (IllegalArgumentException expected) {
             }
         }
 
-        portNumber = Support_PortManager.getNextPort();
         try {
-            ssl = new mySSLServerSocket(portNumber, 1);
-            new mySSLServerSocket(portNumber, 1);
+            new mySSLServerSocket(ssl.getLocalPort(), 1);
             fail("IOException should be thrown");
-        } catch (IOException ioe) {
+        } catch (IOException expected) {
         }
     }
 
     /**
      * javax.net.ssl.SSLServerSocket#SSLServerSocket(int port, int backlog, InetAddress address)
      */
-    public void testConstructor_04() {
-        mySSLServerSocket ssl;
-        InetAddress ia = null;
-        int portNumber = Support_PortManager.getNextPort();
+    public void testConstructor_IIInetAddress() throws Exception {
+        // A null InetAddress is okay.
+        new mySSLServerSocket(0, 0, null);
+
         int[] port_invalid = {-1, 65536, Integer.MIN_VALUE, Integer.MAX_VALUE};
 
-        try {
-            ssl = new mySSLServerSocket(portNumber, 0, ia);
-            assertEquals(portNumber, ssl.getLocalPort());
-        } catch (Exception ex) {
-            fail("Unexpected exception was thrown");
-        }
-
-        portNumber = Support_PortManager.getNextPort();
-        try {
-            ssl = new mySSLServerSocket(portNumber, 0, InetAddress.getLocalHost());
-            assertEquals(portNumber, ssl.getLocalPort());
-        } catch (Exception ex) {
-            fail("Unexpected exception was thrown");
-        }
+        mySSLServerSocket ssl = new mySSLServerSocket(0, 0, InetAddress.getLocalHost());
 
         for (int i = 0; i < port_invalid.length; i++) {
             try {
-                ssl = new mySSLServerSocket(port_invalid[i], 1, InetAddress.getLocalHost());
+                new mySSLServerSocket(port_invalid[i], 1, InetAddress.getLocalHost());
                 fail("IllegalArgumentException should be thrown");
-            } catch (IllegalArgumentException iae) {
-                // expected
-            } catch (Exception e) {
-                fail(e + " was thrown instead of IllegalArgumentException");
+            } catch (IllegalArgumentException expected) {
             }
         }
 
-        portNumber = Support_PortManager.getNextPort();
         try {
-           ssl = new mySSLServerSocket(portNumber, 0, InetAddress.getLocalHost());
-           new mySSLServerSocket(portNumber, 0, InetAddress.getLocalHost());
-           fail("IOException should be thrown for");
-        } catch (IOException ioe) {
+            new mySSLServerSocket(ssl.getLocalPort(), 0, InetAddress.getLocalHost());
+            fail("IOException should be thrown for");
+        } catch (IOException expected) {
         }
     }
 
diff --git a/luni/src/test/java/tests/api/javax/net/ssl/SSLSessionTest.java b/luni/src/test/java/tests/api/javax/net/ssl/SSLSessionTest.java
index ec23cae..5084422 100644
--- a/luni/src/test/java/tests/api/javax/net/ssl/SSLSessionTest.java
+++ b/luni/src/test/java/tests/api/javax/net/ssl/SSLSessionTest.java
@@ -39,12 +39,7 @@
 import libcore.io.Base64;
 import tests.api.javax.net.ssl.HandshakeCompletedEventTest.MyHandshakeListener;
 import tests.api.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
-import tests.support.Support_PortManager;
 
-/**
- * Tests for SSLSession class
- *
- */
 public class SSLSessionTest extends TestCase {
 
     // set to true if on Android, false if on RI
@@ -57,7 +52,7 @@
     public void test_getPeerHost() throws Exception {
         SSLSession s = clientSession;
         assertEquals(InetAddress.getLocalHost().getHostName(), s.getPeerHost());
-        assertEquals(port, s.getPeerPort());
+        assertEquals(serverSocket.getLocalPort(), s.getPeerPort());
     }
 
     /**
@@ -258,12 +253,10 @@
     TestClient client;
 
     @Override
-    protected void setUp() {
-        port = Support_PortManager.getNextPort();
+    protected void setUp() throws Exception {
         String serverKeys = (useBKS ? SERVER_KEYS_BKS : SERVER_KEYS_JKS);
         String clientKeys = (useBKS ? CLIENT_KEYS_BKS : CLIENT_KEYS_JKS);
-        server = new TestServer(true,
-                TestServer.CLIENT_AUTH_WANTED, serverKeys);
+        server = new TestServer(true, TestServer.CLIENT_AUTH_WANTED, serverKeys);
         client = new TestClient(true, clientKeys);
 
         serverThread = new Thread(server);
@@ -453,8 +446,7 @@
             + "NMGpCX6qmjbkJQLVK/Yfo1ePaUexPSOX0G9m8+DoV3iyNw6at01NRw==";
 
 
-    int port;
-    SSLSocket serverSocket;
+    SSLServerSocket serverSocket;
     MyHandshakeListener listener;
     String host = "localhost";
     boolean notFinished = true;
@@ -489,36 +481,35 @@
 
         private KeyStore store;
 
-        public TestServer(boolean provideKeys, int clientAuth, String keys) {
+        public TestServer(boolean provideKeys, int clientAuth, String keys) throws Exception {
             this.keys = keys;
             this.clientAuth = clientAuth;
             this.provideKeys = provideKeys;
 
             trustManager = new TestTrustManager();
+
+            store = provideKeys ? getKeyStore(keys) : null;
+            KeyManager[] keyManagers = store != null ? getKeyManagers(store) : null;
+            TrustManager[] trustManagers = new TrustManager[] { trustManager };
+
+            SSLContext sslContext = SSLContext.getInstance("TLS");
+            sslContext.init(keyManagers, trustManagers, null);
+
+            serverSocket = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket();
+
+            if (clientAuth == CLIENT_AUTH_WANTED) {
+                serverSocket.setWantClientAuth(true);
+            } else if (clientAuth == CLIENT_AUTH_NEEDED) {
+                serverSocket.setNeedClientAuth(true);
+            } else {
+                serverSocket.setWantClientAuth(false);
+            }
+
+            serverSocket.bind(null);
         }
 
         public void run() {
             try {
-                store = provideKeys ? getKeyStore(keys) : null;
-                KeyManager[] keyManagers = store != null ? getKeyManagers(store) : null;
-                TrustManager[] trustManagers = new TrustManager[] { trustManager };
-
-                SSLContext sslContext = SSLContext.getInstance("TLS");
-                sslContext.init(keyManagers, trustManagers, null);
-
-                SSLServerSocket serverSocket = (SSLServerSocket)sslContext
-                        .getServerSocketFactory().createServerSocket();
-
-                if (clientAuth == CLIENT_AUTH_WANTED) {
-                    serverSocket.setWantClientAuth(true);
-                } else if (clientAuth == CLIENT_AUTH_NEEDED) {
-                    serverSocket.setNeedClientAuth(true);
-                } else {
-                    serverSocket.setWantClientAuth(false);
-                }
-
-                serverSocket.bind(new InetSocketAddress(port));
-
                 SSLSocket clientSocket = (SSLSocket)serverSocket.accept();
 
                 InputStream istream = clientSocket.getInputStream();
@@ -589,7 +580,7 @@
 
                 SSLSocket socket = (SSLSocket)clientSslContext.getSocketFactory().createSocket();
 
-                socket.connect(new InetSocketAddress(port));
+                socket.connect(serverSocket.getLocalSocketAddress());
                 OutputStream ostream = socket.getOutputStream();
                 ostream.write(testData.getBytes());
                 ostream.flush();
diff --git a/luni/src/test/java/tests/api/javax/net/ssl/SSLSocketFactoryTest.java b/luni/src/test/java/tests/api/javax/net/ssl/SSLSocketFactoryTest.java
index 02abcc2..0d91116 100644
--- a/luni/src/test/java/tests/api/javax/net/ssl/SSLSocketFactoryTest.java
+++ b/luni/src/test/java/tests/api/javax/net/ssl/SSLSocketFactoryTest.java
@@ -25,16 +25,13 @@
 
 import junit.framework.TestCase;
 
-import tests.support.Support_PortManager;
-
 public class SSLSocketFactoryTest extends TestCase {
 
     private ServerSocket ss;
 
     protected int startServer(String name) {
-        int portNumber = Support_PortManager.getNextPort();
         try {
-            ss = new ServerSocket(portNumber);
+            ss = new ServerSocket(0);
         } catch (IOException e) {
             fail(name + ": " + e);
         }
diff --git a/luni/src/test/java/tests/api/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/tests/api/javax/net/ssl/SSLSocketTest.java
index ab60f72..b4cbde2 100644
--- a/luni/src/test/java/tests/api/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/tests/api/javax/net/ssl/SSLSocketTest.java
@@ -38,7 +38,6 @@
 import junit.framework.TestCase;
 import libcore.io.Base64;
 import tests.api.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
-import tests.support.Support_PortManager;
 import libcore.java.security.StandardNames;
 
 public class SSLSocketTest extends TestCase {
@@ -51,7 +50,7 @@
     /**
      * javax.net.ssl.SSLSocket#SSLSocket()
      */
-    public void testConstructor_01() throws Exception {
+    public void testConstructor() throws Exception {
         SSLSocket ssl = getSSLSocket();
         assertNotNull(ssl);
         ssl.close();
@@ -60,7 +59,7 @@
     /**
      * javax.net.ssl.SSLSocket#SSLSocket(InetAddress address, int port)
      */
-    public void testConstructor_02() throws UnknownHostException, IOException {
+    public void testConstructor_InetAddressI() throws Exception {
         int sport = startServer("Cons InetAddress,I");
         int[] invalidPort = {-1, Integer.MIN_VALUE, 65536, Integer.MAX_VALUE};
 
@@ -88,15 +87,13 @@
      * javax.net.ssl.SSLSocket#SSLSocket(InetAddress address, int port,
      *                                          InetAddress clientAddress, int clientPort)
      */
-    public void testConstructor_03() throws UnknownHostException, IOException {
+    public void testConstructor_InetAddressIInetAddressI() throws Exception {
         int sport = startServer("Cons InetAddress,I,InetAddress,I");
-        int portNumber = Support_PortManager.getNextPort();
 
         SSLSocket ssl = getSSLSocket(InetAddress.getLocalHost(), sport,
-                                     InetAddress.getLocalHost(), portNumber);
+                                     InetAddress.getLocalHost(), 0);
         assertNotNull(ssl);
         assertEquals(sport, ssl.getPort());
-        assertEquals(portNumber, ssl.getLocalPort());
         ssl.close();
 
         try {
@@ -137,7 +134,7 @@
     /**
      * javax.net.ssl.SSLSocket#SSLSocket(String host, int port)
      */
-    public void testConstructor_04() throws UnknownHostException, IOException {
+    public void testConstructor_StringI() throws Exception {
         int sport = startServer("Cons String,I");
         int[] invalidPort = {-1, Integer.MIN_VALUE, 65536, Integer.MAX_VALUE};
 
@@ -171,28 +168,25 @@
      * javax.net.ssl.SSLSocket#SSLSocket(String host, int port, InetAddress clientAddress,
      *           int clientPort)
      */
-    public void testConstructor_05() throws UnknownHostException, IOException {
+    public void testConstructor_StringIInetAddressI() throws Exception {
         int sport = startServer("Cons String,I,InetAddress,I");
-        int portNumber = Support_PortManager.getNextPort();
         int[] invalidPort = {-1, Integer.MIN_VALUE, 65536, Integer.MAX_VALUE};
 
         SSLSocket ssl = getSSLSocket(InetAddress.getLocalHost().getHostName(), sport,
-                                     InetAddress.getLocalHost(), portNumber);
+                                     InetAddress.getLocalHost(), 0);
         assertNotNull(ssl);
         assertEquals(sport, ssl.getPort());
-        assertEquals(portNumber, ssl.getLocalPort());
 
         try {
-            getSSLSocket("localhost", 8081, InetAddress.getLocalHost(), 8082);
+            getSSLSocket(InetAddress.getLocalHost().getHostName(), 8081, InetAddress.getLocalHost(), 8082);
             fail();
         } catch (IOException expected) {
         }
 
         for (int i = 0; i < invalidPort.length; i++) {
-            portNumber = Support_PortManager.getNextPort();
             try {
                 getSSLSocket(InetAddress.getLocalHost().getHostName(), invalidPort[i],
-                             InetAddress.getLocalHost(), portNumber);
+                             InetAddress.getLocalHost(), 0);
                 fail();
             } catch (IllegalArgumentException expected) {
             }
@@ -204,9 +198,8 @@
             }
         }
 
-        portNumber = Support_PortManager.getNextPort();
         try {
-            getSSLSocket("bla-bla", sport, InetAddress.getLocalHost(), portNumber);
+            getSSLSocket("bla-bla", sport, InetAddress.getLocalHost(), 0);
             fail();
         } catch (UnknownHostException expected) {
         }
@@ -422,12 +415,10 @@
         ssl.close();
     }
 
-    boolean useBKS = !StandardNames.IS_RI;
+    private boolean useBKS = !StandardNames.IS_RI;
 
     private String PASSWORD = "android";
 
-    private int port = Support_PortManager.getNextPort();
-
     private boolean serverReady = false;
 
     /**
@@ -551,7 +542,7 @@
                 SSLServerSocket serverSocket = (SSLServerSocket)
                         sslContext.getServerSocketFactory().createServerSocket();
                 try {
-                    serverSocket.bind(new InetSocketAddress(port));
+                    serverSocket.bind(new InetSocketAddress(0));
                     sport = serverSocket.getLocalPort();
                     serverReady = true;
 
diff --git a/luni/src/test/java/tests/api/org/apache/harmony/kernel/dalvik/ThreadsTest.java b/luni/src/test/java/tests/api/org/apache/harmony/kernel/dalvik/ThreadsTest.java
index 286d4ab..bdc580d 100644
--- a/luni/src/test/java/tests/api/org/apache/harmony/kernel/dalvik/ThreadsTest.java
+++ b/luni/src/test/java/tests/api/org/apache/harmony/kernel/dalvik/ThreadsTest.java
@@ -187,11 +187,10 @@
                 if (! completed) {
                     try {
                         wait(maxWaitMillis);
-                    } catch (InterruptedException ex) {
-                        // Ignore it.
+                    } catch (InterruptedException ignored) {
                     }
                     if (! completed) {
-                        Assert.fail("parker hanging");
+                        Assert.fail("parker hung for more than " + maxWaitMillis + " ms");
                     }
                 }
 
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index e8b29e4..eb53ba5 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -274,6 +274,12 @@
             provide("Signature", "SHA512WITHECDSA");
         }
 
+        // Documented as Standard Names, but do not exit in RI 6
+        if (IS_RI) {
+            unprovide("SSLContext", "TLSv1.1");
+            unprovide("SSLContext", "TLSv1.2");
+        }
+
         // Fixups for dalvik
         if (!IS_RI) {
 
@@ -328,6 +334,11 @@
             unprovide("Signature", "SHA512WithRSA");
             provide("Signature", "SHA512WithRSAEncryption");
 
+            // Added to support Android KeyStore operations
+            provide("Signature", "NONEwithRSA");
+            provide("Cipher", "RSA/ECB/NOPADDING");
+            provide("Cipher", "RSA/ECB/PKCS1PADDING");
+
             // different names: JSSE Reference Guide says PKIX aka X509
             unprovide("TrustManagerFactory", "PKIX");
             provide("TrustManagerFactory", "X509");
diff --git a/support/src/test/java/tests/support/Support_TestWebServer.java b/support/src/test/java/tests/support/Support_TestWebServer.java
index 4d6b0d1..5f3cd85 100644
--- a/support/src/test/java/tests/support/Support_TestWebServer.java
+++ b/support/src/test/java/tests/support/Support_TestWebServer.java
@@ -94,51 +94,21 @@
     }
 
     /**
-     * Initialize a new server with default port and timeout.
-     * @param log Set true if you want trace output
-     */
-    public int initServer(boolean log) throws Exception {
-        return initServer(0, DEFAULT_TIMEOUT, log);
-    }
-
-    /**
-     * Initialize a new server with default timeout.
-     * @param port Sets the server to listen on this port, or 0 to let the OS choose.
-     *             Hard-coding ports is evil, so always pass 0.
-     * @param log Set true if you want trace output
-     */
-    public int initServer(int port, boolean log) throws Exception {
-        return initServer(port, DEFAULT_TIMEOUT, log);
-    }
-
-    /**
-     * Initialize a new server with default timeout and disabled log.
-     * @param port Sets the server to listen on this port, or 0 to let the OS choose.
-     *             Hard-coding ports is evil, so always pass 0.
      * @param servePath the path to the dynamic web test data
      * @param contentType the type of the dynamic web test data
      */
-    public int initServer(int port, String servePath, String contentType)
-            throws Exception {
+    public int initServer(String servePath, String contentType) throws Exception {
         Support_TestWebData.initDynamicTestWebData(servePath, contentType);
-        return initServer(port, DEFAULT_TIMEOUT, false);
+        return initServer();
     }
 
-    /**
-     * Initialize a new server with default port and timeout.
-     * @param port Sets the server to listen on this port, or 0 to let the OS choose.
-     *             Hard-coding ports is evil, so always pass 0.
-     * @param timeout Indicates the period of time to wait until a socket is
-     *                closed
-     * @param log Set true if you want trace output
-     */
-    public int initServer(int port, int timeout, boolean log) throws Exception {
-        mTimeout = timeout;
-        mLog = log;
+    public int initServer() throws Exception {
+        mTimeout = DEFAULT_TIMEOUT;
+        mLog = false;
         keepAlive = true;
         if (acceptT == null) {
             acceptT = new AcceptThread();
-            mPort = acceptT.init(port);
+            mPort = acceptT.init();
             acceptT.start();
         }
         return mPort;
@@ -253,8 +223,8 @@
          * @param port the port to use, or 0 to let the OS choose.
          * Hard-coding ports is evil, so always pass 0!
          */
-        public int init(int port) throws IOException {
-            ss = new ServerSocket(port);
+        public int init() throws IOException {
+            ss = new ServerSocket(0);
             ss.setSoTimeout(5000);
             ss.setReuseAddress(true);
             return ss.getLocalPort();
diff --git a/xml/src/main/java/org/kxml2/ThirdPartyProject.prop b/xml/src/main/java/org/kxml2/ThirdPartyProject.prop
deleted file mode 100644
index aabb1c7..0000000
--- a/xml/src/main/java/org/kxml2/ThirdPartyProject.prop
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2010 Google Inc. All Rights Reserved.
-#Fri Jul 16 10:03:09 PDT 2010
-currentVersion=2.3.0
-version=Unknown
-isNative=false
-name=kxml
-keywords=kxml
-onDevice=true
-homepage=http\://kxml.sourceforge.net/
diff --git a/xml/src/main/java/org/kxml2/kdom/Document.java b/xml/src/main/java/org/kxml2/kdom/Document.java
deleted file mode 100644
index 9123e62..0000000
--- a/xml/src/main/java/org/kxml2/kdom/Document.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The  above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE. */
-
-
-package org.kxml2.kdom;
-
-import java.io.*;
-
-import org.xmlpull.v1.*;
-/** The document consists of some legacy events and a single root
-    element. This class basically adds some consistency checks to
-    Node. */
-
-public class Document extends Node {
-
-    protected int rootIndex = -1;
-    String encoding;
-    Boolean standalone;
-
-    /** returns "#document" */
-
-    public String getEncoding () {
-        return encoding;
-    }
-
-    public void setEncoding(String enc) {
-        this.encoding = enc;
-    }
-
-    public void setStandalone (Boolean standalone) {
-        this.standalone = standalone;
-    }
-
-    public Boolean getStandalone() {
-        return standalone;
-    }
-
-
-    public String getName() {
-        return "#document";
-    }
-
-    /** Adds a child at the given index position. Throws
-    an exception when a second root element is added */
-
-    public void addChild(int index, int type, Object child) {
-        if (type == ELEMENT) {
-         //   if (rootIndex != -1)
-           //     throw new RuntimeException("Only one document root element allowed");
-
-            rootIndex = index;
-        }
-        else if (rootIndex >= index)
-            rootIndex++;
-
-        super.addChild(index, type, child);
-    }
-
-    /** reads the document and checks if the last event
-    is END_DOCUMENT. If not, an exception is thrown.
-    The end event is consumed. For parsing partial
-        XML structures, consider using Node.parse (). */
-
-    public void parse(XmlPullParser parser)
-        throws IOException, XmlPullParserException {
-
-        parser.require(XmlPullParser.START_DOCUMENT, null, null);
-        parser.nextToken ();
-
-        encoding = parser.getInputEncoding();
-        standalone = (Boolean)parser.getProperty ("http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone");
-
-        super.parse(parser);
-
-        if (parser.getEventType() != XmlPullParser.END_DOCUMENT)
-            throw new RuntimeException("Document end expected!");
-
-    }
-
-    public void removeChild(int index) {
-        if (index == rootIndex)
-            rootIndex = -1;
-        else if (index < rootIndex)
-            rootIndex--;
-
-        super.removeChild(index);
-    }
-
-    /** returns the root element of this document. */
-
-    public Element getRootElement() {
-        if (rootIndex == -1)
-            throw new RuntimeException("Document has no root element!");
-
-        return (Element) getChild(rootIndex);
-    }
-
-
-    /** Writes this node to the given XmlWriter. For node and document,
-        this method is identical to writeChildren, except that the
-        stream is flushed automatically. */
-
-    public void write(XmlSerializer writer)
-        throws IOException {
-
-        writer.startDocument(encoding, standalone);
-        writeChildren(writer);
-        writer.endDocument();
-    }
-
-
-}
\ No newline at end of file
diff --git a/xml/src/main/java/org/kxml2/kdom/Element.java b/xml/src/main/java/org/kxml2/kdom/Element.java
deleted file mode 100644
index a9cb426..0000000
--- a/xml/src/main/java/org/kxml2/kdom/Element.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The  above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE. */
-
-package org.kxml2.kdom;
-
-import java.io.*;
-import java.util.*;
-
-import org.xmlpull.v1.*;
-
-/**
- * In order to create an element, please use the createElement method
- * instead of invoking the constructor directly. The right place to
- * add user defined initialization code is the init method. */
-
-public class Element extends Node {
-
-    protected String namespace;
-    protected String name;
-    protected Vector attributes;
-    protected Node parent;
-    protected Vector prefixes;
-
-    public Element() {
-    }
-
-    /**
-     * called when all properties are set, but before children
-     * are parsed. Please do not use setParent for initialization
-     * code any longer. */
-
-    public void init() {
-    }
-
-
-
-
-    /**
-     * removes all children and attributes */
-
-    public void clear() {
-        attributes = null;
-        children = null;
-    }
-
-    /**
-     * Forwards creation request to parent if any, otherwise
-     * calls super.createElement. */
-
-    public Element createElement(
-        String namespace,
-        String name) {
-
-        return (this.parent == null)
-            ? super.createElement(namespace, name)
-            : this.parent.createElement(namespace, name);
-    }
-
-    /**
-     * Returns the number of attributes of this element. */
-
-    public int getAttributeCount() {
-        return attributes == null ? 0 : attributes.size();
-    }
-
-    public String getAttributeNamespace (int index) {
-        return ((String []) attributes.elementAt (index)) [0];
-    }
-
-/*    public String getAttributePrefix (int index) {
-        return ((String []) attributes.elementAt (index)) [1];
-    }*/
-
-    public String getAttributeName (int index) {
-        return ((String []) attributes.elementAt (index)) [1];
-    }
-
-
-    public String getAttributeValue (int index) {
-        return ((String []) attributes.elementAt (index)) [2];
-    }
-
-
-    public String getAttributeValue (String namespace, String name) {
-        for (int i = 0; i < getAttributeCount (); i++) {
-            if (name.equals (getAttributeName (i))
-                && (namespace == null || namespace.equals (getAttributeNamespace(i)))) {
-                return getAttributeValue (i);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns the root node, determined by ascending to the
-     * all parents un of the root element. */
-
-    public Node getRoot() {
-
-        Element current = this;
-
-        while (current.parent != null) {
-            if (!(current.parent instanceof Element)) return current.parent;
-            current = (Element) current.parent;
-        }
-
-        return current;
-    }
-
-    /**
-     * returns the (local) name of the element */
-
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * returns the namespace of the element */
-
-    public String getNamespace() {
-        return namespace;
-    }
-
-
-    /**
-     * returns the namespace for the given prefix */
-
-    public String getNamespaceUri (String prefix) {
-        int cnt = getNamespaceCount ();
-        for (int i = 0; i < cnt; i++) {
-            if (prefix == getNamespacePrefix (i) ||
-                (prefix != null && prefix.equals (getNamespacePrefix (i))))
-                return getNamespaceUri (i);
-        }
-        return parent instanceof Element ? ((Element) parent).getNamespaceUri (prefix) : null;
-    }
-
-
-    /**
-     * returns the number of declared namespaces, NOT including
-     * parent elements */
-
-    public int getNamespaceCount () {
-        return (prefixes == null ? 0 : prefixes.size ());
-    }
-
-
-    public String getNamespacePrefix (int i) {
-        return ((String []) prefixes.elementAt (i)) [0];
-    }
-
-    public String getNamespaceUri (int i) {
-        return ((String []) prefixes.elementAt (i)) [1];
-    }
-
-
-    /**
-     * Returns the parent node of this element */
-
-    public Node getParent() {
-        return parent;
-    }
-
-    /*
-     * Returns the parent element if available, null otherwise
-
-    public Element getParentElement() {
-        return (parent instanceof Element)
-            ? ((Element) parent)
-            : null;
-    }
-*/
-
-    /**
-     * Builds the child elements from the given Parser. By overwriting
-     * parse, an element can take complete control over parsing its
-     * subtree. */
-
-    public void parse(XmlPullParser parser)
-        throws IOException, XmlPullParserException {
-
-        for (int i = parser.getNamespaceCount (parser.getDepth () - 1);
-            i < parser.getNamespaceCount (parser.getDepth ()); i++) {
-            setPrefix (parser.getNamespacePrefix (i), parser.getNamespaceUri(i));
-        }
-
-
-        for (int i = 0; i < parser.getAttributeCount (); i++)
-            setAttribute (parser.getAttributeNamespace (i),
-//                          parser.getAttributePrefix (i),
-                          parser.getAttributeName (i),
-                          parser.getAttributeValue (i));
-
-
-        //        if (prefixMap == null) throw new RuntimeException ("!!");
-
-        init();
-
-
-        if (parser.isEmptyElementTag())
-            parser.nextToken ();
-        else {
-            parser.nextToken ();
-            super.parse(parser);
-
-            if (getChildCount() == 0)
-                addChild(IGNORABLE_WHITESPACE, "");
-        }
-
-        parser.require(
-            XmlPullParser.END_TAG,
-            getNamespace(),
-            getName());
-
-        parser.nextToken ();
-    }
-
-
-    /**
-     * Sets the given attribute; a value of null removes the attribute */
-
-    public void setAttribute (String namespace, String name, String value) {
-        if (attributes == null)
-            attributes = new Vector ();
-
-        if (namespace == null)
-            namespace = "";
-
-        for (int i = attributes.size()-1; i >=0; i--){
-            String[] attribut = (String[]) attributes.elementAt(i);
-            if (attribut[0].equals(namespace) &&
-                attribut[1].equals(name)){
-
-                if (value == null) {
-                    attributes.removeElementAt(i);
-                }
-                else {
-                    attribut[2] = value;
-                }
-                return;
-            }
-        }
-
-        attributes.addElement
-            (new String [] {namespace, name, value});
-    }
-
-
-    /**
-     * Sets the given prefix; a namespace value of null removess the
-     * prefix */
-
-    public void setPrefix (String prefix, String namespace) {
-        if (prefixes == null) prefixes = new Vector ();
-        prefixes.addElement (new String [] {prefix, namespace});
-    }
-
-
-    /**
-     * sets the name of the element */
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * sets the namespace of the element. Please note: For no
-     * namespace, please use Xml.NO_NAMESPACE, null is not a legal
-     * value. Currently, null is converted to Xml.NO_NAMESPACE, but
-     * future versions may throw an exception. */
-
-    public void setNamespace(String namespace) {
-        if (namespace == null)
-            throw new NullPointerException ("Use \"\" for empty namespace");
-        this.namespace = namespace;
-    }
-
-    /**
-     * Sets the Parent of this element. Automatically called from the
-     * add method.  Please use with care, you can simply
-     * create inconsitencies in the document tree structure using
-     * this method!  */
-
-    protected void setParent(Node parent) {
-        this.parent = parent;
-    }
-
-
-    /**
-     * Writes this element and all children to the given XmlWriter. */
-
-    public void write(XmlSerializer writer)
-        throws IOException {
-
-        if (prefixes != null) {
-            for (int i = 0; i < prefixes.size(); i++) {
-                writer.setPrefix (getNamespacePrefix (i), getNamespaceUri (i));
-            }
-        }
-
-        writer.startTag(
-            getNamespace(),
-            getName());
-
-        int len = getAttributeCount();
-
-        for (int i = 0; i < len; i++) {
-            writer.attribute(
-                getAttributeNamespace(i),
-                getAttributeName(i),
-                getAttributeValue(i));
-        }
-
-        writeChildren(writer);
-
-        writer.endTag(getNamespace (), getName ());
-    }
-}
diff --git a/xml/src/main/java/org/kxml2/kdom/Node.java b/xml/src/main/java/org/kxml2/kdom/Node.java
deleted file mode 100644
index 820390c..0000000
--- a/xml/src/main/java/org/kxml2/kdom/Node.java
+++ /dev/null
@@ -1,366 +0,0 @@
-/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The  above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE. */
-
-package org.kxml2.kdom;
-
-import java.util.*;
-import java.io.*;
-import org.xmlpull.v1.*;
-/** A common base class for Document and Element, also used for
-    storing XML fragments. */
-
-public class Node { //implements XmlIO{
-
-    public static final int DOCUMENT = 0;
-    public static final int ELEMENT = 2;
-    public static final int TEXT = 4;
-    public static final int CDSECT = 5;
-    public static final int ENTITY_REF = 6;
-    public static final int IGNORABLE_WHITESPACE = 7;
-    public static final int PROCESSING_INSTRUCTION = 8;
-    public static final int COMMENT = 9;
-    public static final int DOCDECL = 10;
-
-    protected Vector children;
-    protected StringBuffer types;
-
-    /** inserts the given child object of the given type at the
-    given index. */
-
-    public void addChild(int index, int type, Object child) {
-
-        if (child == null)
-            throw new NullPointerException();
-
-        if (children == null) {
-            children = new Vector();
-            types = new StringBuffer();
-        }
-
-        if (type == ELEMENT) {
-            if (!(child instanceof Element))
-                throw new RuntimeException("Element obj expected)");
-
-            ((Element) child).setParent(this);
-        }
-        else if (!(child instanceof String))
-            throw new RuntimeException("String expected");
-
-        children.insertElementAt(child, index);
-        types.insert(index, (char) type);
-    }
-
-    /** convenience method for addChild (getChildCount (), child) */
-
-    public void addChild(int type, Object child) {
-        addChild(getChildCount(), type, child);
-    }
-
-    /** Builds a default element with the given properties. Elements
-    should always be created using this method instead of the
-    constructor in order to enable construction of specialized
-    subclasses by deriving custom Document classes. Please note:
-    For no namespace, please use Xml.NO_NAMESPACE, null is not a
-    legal value. Currently, null is converted to Xml.NO_NAMESPACE,
-    but future versions may throw an exception. */
-
-    public Element createElement(String namespace, String name) {
-
-        Element e = new Element();
-        e.namespace = namespace == null ? "" : namespace;
-        e.name = name;
-        return e;
-    }
-
-    /** Returns the child object at the given index.  For child
-        elements, an Element object is returned. For all other child
-        types, a String is returned. */
-
-    public Object getChild(int index) {
-        return children.elementAt(index);
-    }
-
-    /** Returns the number of child objects */
-
-    public int getChildCount() {
-        return children == null ? 0 : children.size();
-    }
-
-    /** returns the element at the given index. If the node at the
-    given index is a text node, null is returned */
-
-    public Element getElement(int index) {
-        Object child = getChild(index);
-        return (child instanceof Element) ? (Element) child : null;
-    }
-
-    /** Returns the element with the given namespace and name. If the
-        element is not found, or more than one matching elements are
-        found, an exception is thrown. */
-
-    public Element getElement(String namespace, String name) {
-
-        int i = indexOf(namespace, name, 0);
-        int j = indexOf(namespace, name, i + 1);
-
-        if (i == -1 || j != -1)
-            throw new RuntimeException(
-                "Element {"
-                    + namespace
-                    + "}"
-                    + name
-                    + (i == -1 ? " not found in " : " more than once in ")
-                    + this);
-
-        return getElement(i);
-    }
-
-    /* returns "#document-fragment". For elements, the element name is returned
-
-    public String getName() {
-        return "#document-fragment";
-    }
-
-    /** Returns the namespace of the current element. For Node
-        and Document, Xml.NO_NAMESPACE is returned.
-
-    public String getNamespace() {
-        return "";
-    }
-
-    public int getNamespaceCount () {
-        return 0;
-    }
-
-    /** returns the text content if the element has text-only
-    content. Throws an exception for mixed content
-
-    public String getText() {
-
-        StringBuffer buf = new StringBuffer();
-        int len = getChildCount();
-
-        for (int i = 0; i < len; i++) {
-            if (isText(i))
-                buf.append(getText(i));
-            else if (getType(i) == ELEMENT)
-                throw new RuntimeException("not text-only content!");
-        }
-
-        return buf.toString();
-    }
-    */
-
-    /** Returns the text node with the given index or null if the node
-        with the given index is not a text node. */
-
-    public String getText(int index) {
-        return (isText(index)) ? (String) getChild(index) : null;
-    }
-
-    /** Returns the type of the child at the given index. Possible
-    types are ELEMENT, TEXT, COMMENT, and PROCESSING_INSTRUCTION */
-
-    public int getType(int index) {
-        return types.charAt(index);
-    }
-
-    /** Convenience method for indexOf (getNamespace (), name,
-        startIndex).
-
-    public int indexOf(String name, int startIndex) {
-        return indexOf(getNamespace(), name, startIndex);
-    }
-    */
-
-    /** Performs search for an element with the given namespace and
-    name, starting at the given start index. A null namespace
-    matches any namespace, please use Xml.NO_NAMESPACE for no
-    namespace).  returns -1 if no matching element was found. */
-
-    public int indexOf(String namespace, String name, int startIndex) {
-
-        int len = getChildCount();
-
-        for (int i = startIndex; i < len; i++) {
-
-            Element child = getElement(i);
-
-            if (child != null
-                && name.equals(child.getName())
-                && (namespace == null || namespace.equals(child.getNamespace())))
-                return i;
-        }
-        return -1;
-    }
-
-    public boolean isText(int i) {
-        int t = getType(i);
-        return t == TEXT || t == IGNORABLE_WHITESPACE || t == CDSECT;
-    }
-
-    /** Recursively builds the child elements from the given parser
-    until an end tag or end document is found.
-        The end tag is not consumed. */
-
-    public void parse(XmlPullParser parser)
-        throws IOException, XmlPullParserException {
-
-        boolean leave = false;
-
-        do {
-            int type = parser.getEventType();
-
-   //         System.out.println(parser.getPositionDescription());
-
-            switch (type) {
-
-                case XmlPullParser.START_TAG :
-                    {
-                        Element child =
-                            createElement(
-                                parser.getNamespace(),
-                                parser.getName());
-                        //    child.setAttributes (event.getAttributes ());
-                        addChild(ELEMENT, child);
-
-                        // order is important here since
-                        // setparent may perform some init code!
-
-                        child.parse(parser);
-                        break;
-                    }
-
-                case XmlPullParser.END_DOCUMENT :
-                case XmlPullParser.END_TAG :
-                    leave = true;
-                    break;
-
-                default :
-                    if (parser.getText() != null)
-                        addChild(
-                            type == XmlPullParser.ENTITY_REF ? TEXT : type,
-                            parser.getText());
-                    else if (
-                        type == XmlPullParser.ENTITY_REF
-                            && parser.getName() != null) {
-                        addChild(ENTITY_REF, parser.getName());
-                    }
-                    parser.nextToken();
-            }
-        }
-        while (!leave);
-    }
-
-    /** Removes the child object at the given index */
-
-    public void removeChild(int idx) {
-        children.removeElementAt(idx);
-
-        /***  Modification by HHS - start ***/
-        //      types.deleteCharAt (index);
-        /***/
-        int n = types.length() - 1;
-
-        for (int i = idx; i < n; i++)
-            types.setCharAt(i, types.charAt(i + 1));
-
-        types.setLength(n);
-
-        /***  Modification by HHS - end   ***/
-    }
-
-    /* returns a valid XML representation of this Element including
-        attributes and children.
-    public String toString() {
-        try {
-            ByteArrayOutputStream bos =
-                new ByteArrayOutputStream();
-            XmlWriter xw =
-                new XmlWriter(new OutputStreamWriter(bos));
-            write(xw);
-            xw.close();
-            return new String(bos.toByteArray());
-        }
-        catch (IOException e) {
-            throw new RuntimeException(e.toString());
-        }
-    }
-    */
-
-    /** Writes this node to the given XmlWriter. For node and document,
-        this method is identical to writeChildren, except that the
-        stream is flushed automatically. */
-
-    public void write(XmlSerializer writer) throws IOException {
-        writeChildren(writer);
-        writer.flush();
-    }
-
-    /** Writes the children of this node to the given XmlWriter. */
-
-    public void writeChildren(XmlSerializer writer) throws IOException {
-        if (children == null)
-            return;
-
-        int len = children.size();
-
-        for (int i = 0; i < len; i++) {
-            int type = getType(i);
-            Object child = children.elementAt(i);
-            switch (type) {
-                case ELEMENT :
-                     ((Element) child).write(writer);
-                    break;
-
-                case TEXT :
-                    writer.text((String) child);
-                    break;
-
-                case IGNORABLE_WHITESPACE :
-                    writer.ignorableWhitespace((String) child);
-                    break;
-
-                case CDSECT :
-                    writer.cdsect((String) child);
-                    break;
-
-                case COMMENT :
-                    writer.comment((String) child);
-                    break;
-
-                case ENTITY_REF :
-                    writer.entityRef((String) child);
-                    break;
-
-                case PROCESSING_INSTRUCTION :
-                    writer.processingInstruction((String) child);
-                    break;
-
-                case DOCDECL :
-                    writer.docdecl((String) child);
-                    break;
-
-                default :
-                    throw new RuntimeException("Illegal type: " + type);
-            }
-        }
-    }
-}
diff --git a/xml/src/main/java/org/xml/ThirdPartyProject.prop b/xml/src/main/java/org/xml/ThirdPartyProject.prop
deleted file mode 100644
index b8ac0da..0000000
--- a/xml/src/main/java/org/xml/ThirdPartyProject.prop
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2010 Google Inc. All Rights Reserved.
-#Fri Jul 16 10:03:09 PDT 2010
-currentVersion=2.0.2
-version=2.0.2
-isNative=false
-name=xml_sax_parser
-keywords=xml sax parser
-onDevice=true
-homepage=http\://www.saxproject.org
diff --git a/xml/src/main/java/org/xmlpull/ThirdPartyProject.prop b/xml/src/main/java/org/xmlpull/ThirdPartyProject.prop
deleted file mode 100644
index 9ccbf09..0000000
--- a/xml/src/main/java/org/xmlpull/ThirdPartyProject.prop
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2010 Google Inc. All Rights Reserved.
-#Fri Jul 16 10:03:09 PDT 2010
-currentVersion=1.1.3.4c
-version=Unknown
-isNative=false
-name=xml_pull_parser
-keywords=xml pull parser
-onDevice=true
-homepage=http\://xmlpull.org